projscan 1.7.0 → 1.8.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/core/applyFix.js +5 -46
- package/dist/core/applyFix.js.map +1 -1
- package/dist/core/embeddings.d.ts +9 -0
- package/dist/core/embeddings.js +45 -5
- package/dist/core/embeddings.js.map +1 -1
- package/dist/core/languages/LanguageAdapter.d.ts +1 -1
- package/dist/core/languages/cppFunctions.js +40 -1
- package/dist/core/languages/cppFunctions.js.map +1 -1
- package/dist/core/languages/registry.js +2 -0
- package/dist/core/languages/registry.js.map +1 -1
- package/dist/core/languages/swiftAdapter.d.ts +2 -0
- package/dist/core/languages/swiftAdapter.js +130 -0
- package/dist/core/languages/swiftAdapter.js.map +1 -0
- package/dist/core/languages/swiftCallSites.d.ts +14 -0
- package/dist/core/languages/swiftCallSites.js +60 -0
- package/dist/core/languages/swiftCallSites.js.map +1 -0
- package/dist/core/languages/swiftCyclomatic.d.ts +24 -0
- package/dist/core/languages/swiftCyclomatic.js +54 -0
- package/dist/core/languages/swiftCyclomatic.js.map +1 -0
- package/dist/core/languages/swiftExports.d.ts +13 -0
- package/dist/core/languages/swiftExports.js +95 -0
- package/dist/core/languages/swiftExports.js.map +1 -0
- package/dist/core/languages/swiftFunctions.d.ts +28 -0
- package/dist/core/languages/swiftFunctions.js +162 -0
- package/dist/core/languages/swiftFunctions.js.map +1 -0
- package/dist/core/languages/swiftImports.d.ts +26 -0
- package/dist/core/languages/swiftImports.js +45 -0
- package/dist/core/languages/swiftImports.js.map +1 -0
- package/dist/core/languages/swiftManifests.d.ts +17 -0
- package/dist/core/languages/swiftManifests.js +49 -0
- package/dist/core/languages/swiftManifests.js.map +1 -0
- package/dist/core/languages/treeSitterLoader.js +2 -0
- package/dist/core/languages/treeSitterLoader.js.map +1 -1
- package/dist/core/session.d.ts +18 -4
- package/dist/core/session.js +20 -5
- package/dist/core/session.js.map +1 -1
- package/dist/core/taint.d.ts +17 -0
- package/dist/core/taint.js +19 -1
- package/dist/core/taint.js.map +1 -1
- package/dist/grammars/tree-sitter-swift.wasm +0 -0
- package/dist/mcp/server.js +60 -1
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/tools/_shared.d.ts +25 -1
- package/dist/mcp/tools/_shared.js.map +1 -1
- package/dist/mcp/tools/costSummary.js +12 -3
- package/dist/mcp/tools/costSummary.js.map +1 -1
- package/dist/mcp/tools/reviewWatch.d.ts +7 -0
- package/dist/mcp/tools/reviewWatch.js +228 -0
- package/dist/mcp/tools/reviewWatch.js.map +1 -0
- package/dist/mcp/tools.js +2 -0
- package/dist/mcp/tools.js.map +1 -1
- package/dist/tool-manifest.json +37 -3
- package/dist/utils/atomicWrite.d.ts +26 -0
- package/dist/utils/atomicWrite.js +69 -0
- package/dist/utils/atomicWrite.js.map +1 -0
- package/package.json +3 -2
package/dist/tool-manifest.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "projscan",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.0",
|
|
4
4
|
"mcpProtocolVersion": "2025-03-26",
|
|
5
|
-
"generatedAt": "2026-05-
|
|
6
|
-
"toolCount":
|
|
5
|
+
"generatedAt": "2026-05-07T22:25:02.535Z",
|
|
6
|
+
"toolCount": 27,
|
|
7
7
|
"tools": [
|
|
8
8
|
{
|
|
9
9
|
"name": "projscan_analyze",
|
|
@@ -655,6 +655,40 @@
|
|
|
655
655
|
}
|
|
656
656
|
}
|
|
657
657
|
}
|
|
658
|
+
},
|
|
659
|
+
{
|
|
660
|
+
"name": "projscan_review_watch",
|
|
661
|
+
"description": "Long-running PR review. Polls a base+head ref pair on an interval and emits a notifications/projscan/pr_changed notification whenever the review verdict, SHAs, flow count, or risky-function set changes. Pairs with projscan_review (one-shot) — use this when an agent wants to react to pushes on a PR without re-asking. Actions: start (returns initial review + watchId) / stop / list.",
|
|
662
|
+
"inputSchema": {
|
|
663
|
+
"type": "object",
|
|
664
|
+
"properties": {
|
|
665
|
+
"action": {
|
|
666
|
+
"type": "string",
|
|
667
|
+
"enum": [
|
|
668
|
+
"start",
|
|
669
|
+
"stop",
|
|
670
|
+
"list"
|
|
671
|
+
],
|
|
672
|
+
"description": "\"start\" begins polling (returns initial review + watchId). \"stop\" cancels a watch by id. \"list\" enumerates active watches."
|
|
673
|
+
},
|
|
674
|
+
"base": {
|
|
675
|
+
"type": "string",
|
|
676
|
+
"description": "Base ref. Default: origin/main → main → origin/master → master → HEAD~1. (start only)"
|
|
677
|
+
},
|
|
678
|
+
"head": {
|
|
679
|
+
"type": "string",
|
|
680
|
+
"description": "Head ref. Default: HEAD. (start only)"
|
|
681
|
+
},
|
|
682
|
+
"interval_seconds": {
|
|
683
|
+
"type": "number",
|
|
684
|
+
"description": "Poll interval in seconds. Default: 30. Min: 5, max: 600. (start only)"
|
|
685
|
+
},
|
|
686
|
+
"watchId": {
|
|
687
|
+
"type": "string",
|
|
688
|
+
"description": "Watch identifier returned by a previous \"start\". (stop only)"
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
}
|
|
658
692
|
}
|
|
659
693
|
]
|
|
660
694
|
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Crash-safe file write: write to a tmp path, fsync the data, rename
|
|
3
|
+
* over the target, then best-effort fsync the parent directory.
|
|
4
|
+
*
|
|
5
|
+
* Three hardenings over a naive writeFile + rename:
|
|
6
|
+
*
|
|
7
|
+
* 1. Tmp filename uses randomUUID() so the path is unpredictable. A
|
|
8
|
+
* shared-system attacker can't pre-create a symlink at the tmp path
|
|
9
|
+
* before our write lands.
|
|
10
|
+
*
|
|
11
|
+
* 2. Open with the 'wx' flag (O_CREAT | O_EXCL). If the tmp path
|
|
12
|
+
* already exists for any reason (race, leftover, planted symlink),
|
|
13
|
+
* fs.open throws EEXIST instead of following the symlink. Belt-
|
|
14
|
+
* and-suspenders with #1.
|
|
15
|
+
*
|
|
16
|
+
* 3. fsync the file before rename, and best-effort fsync the parent
|
|
17
|
+
* dir after rename. Rename is atomic at the journal-record level
|
|
18
|
+
* on most filesystems, but without fsync the rename can survive a
|
|
19
|
+
* crash with empty tmp content (file metadata persists, data
|
|
20
|
+
* doesn't). Parent-dir sync is best-effort: Windows doesn't
|
|
21
|
+
* support it and some FUSE backends treat it as a no-op.
|
|
22
|
+
*
|
|
23
|
+
* Used by `applyFix` (1.6+) and `session.saveSession` (1.8+) to ensure
|
|
24
|
+
* that crashes mid-write never leave partially-written state on disk.
|
|
25
|
+
*/
|
|
26
|
+
export declare function atomicWriteFile(absPath: string, content: string): Promise<void>;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { randomUUID } from 'node:crypto';
|
|
4
|
+
/**
|
|
5
|
+
* Crash-safe file write: write to a tmp path, fsync the data, rename
|
|
6
|
+
* over the target, then best-effort fsync the parent directory.
|
|
7
|
+
*
|
|
8
|
+
* Three hardenings over a naive writeFile + rename:
|
|
9
|
+
*
|
|
10
|
+
* 1. Tmp filename uses randomUUID() so the path is unpredictable. A
|
|
11
|
+
* shared-system attacker can't pre-create a symlink at the tmp path
|
|
12
|
+
* before our write lands.
|
|
13
|
+
*
|
|
14
|
+
* 2. Open with the 'wx' flag (O_CREAT | O_EXCL). If the tmp path
|
|
15
|
+
* already exists for any reason (race, leftover, planted symlink),
|
|
16
|
+
* fs.open throws EEXIST instead of following the symlink. Belt-
|
|
17
|
+
* and-suspenders with #1.
|
|
18
|
+
*
|
|
19
|
+
* 3. fsync the file before rename, and best-effort fsync the parent
|
|
20
|
+
* dir after rename. Rename is atomic at the journal-record level
|
|
21
|
+
* on most filesystems, but without fsync the rename can survive a
|
|
22
|
+
* crash with empty tmp content (file metadata persists, data
|
|
23
|
+
* doesn't). Parent-dir sync is best-effort: Windows doesn't
|
|
24
|
+
* support it and some FUSE backends treat it as a no-op.
|
|
25
|
+
*
|
|
26
|
+
* Used by `applyFix` (1.6+) and `session.saveSession` (1.8+) to ensure
|
|
27
|
+
* that crashes mid-write never leave partially-written state on disk.
|
|
28
|
+
*/
|
|
29
|
+
export async function atomicWriteFile(absPath, content) {
|
|
30
|
+
const tmp = `${absPath}.projscan-tmp-${randomUUID()}`;
|
|
31
|
+
const handle = await fs.open(tmp, 'wx');
|
|
32
|
+
try {
|
|
33
|
+
await handle.writeFile(content, 'utf-8');
|
|
34
|
+
await handle.sync();
|
|
35
|
+
}
|
|
36
|
+
finally {
|
|
37
|
+
await handle.close();
|
|
38
|
+
}
|
|
39
|
+
// 1.8+ — clean up the tmp file if rename fails (e.g., the target is
|
|
40
|
+
// on a read-only filesystem, EACCES, or its parent dir was removed
|
|
41
|
+
// mid-write). Without this, retried writes leak abandoned tmp files
|
|
42
|
+
// forever — invisible until they pile up. Re-throw the original
|
|
43
|
+
// error so callers see the real cause; the unlink is best-effort.
|
|
44
|
+
try {
|
|
45
|
+
await fs.rename(tmp, absPath);
|
|
46
|
+
}
|
|
47
|
+
catch (err) {
|
|
48
|
+
try {
|
|
49
|
+
await fs.unlink(tmp);
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
// best-effort cleanup
|
|
53
|
+
}
|
|
54
|
+
throw err;
|
|
55
|
+
}
|
|
56
|
+
try {
|
|
57
|
+
const dir = await fs.open(path.dirname(absPath), 'r');
|
|
58
|
+
try {
|
|
59
|
+
await dir.sync();
|
|
60
|
+
}
|
|
61
|
+
finally {
|
|
62
|
+
await dir.close();
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
// ignore — best-effort
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=atomicWrite.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"atomicWrite.js","sourceRoot":"","sources":["../../src/utils/atomicWrite.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,OAAe,EAAE,OAAe;IACpE,MAAM,GAAG,GAAG,GAAG,OAAO,iBAAiB,UAAU,EAAE,EAAE,CAAC;IACtD,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IACxC,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACzC,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;IACtB,CAAC;YAAS,CAAC;QACT,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC;IACD,oEAAoE;IACpE,mEAAmE;IACnE,oEAAoE;IACpE,gEAAgE;IAChE,kEAAkE;IAClE,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,MAAM,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IAChC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,CAAC;YACH,MAAM,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACvB,CAAC;QAAC,MAAM,CAAC;YACP,sBAAsB;QACxB,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;IACD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,GAAG,CAAC,CAAC;QACtD,IAAI,CAAC;YACH,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;QACnB,CAAC;gBAAS,CAAC;YACT,MAAM,GAAG,CAAC,KAAK,EAAE,CAAC;QACpB,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,uBAAuB;IACzB,CAAC;AACH,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "projscan",
|
|
3
3
|
"mcpName": "io.github.abhiyoheswaran1/projscan",
|
|
4
|
-
"version": "1.
|
|
5
|
-
"description": "Agent-first code intelligence. MCP server (2025-03-26) with AST parsing for JavaScript, TypeScript, Python, Go, Java, Ruby, Rust, PHP, C#, Kotlin, and C++; code graph, file + per-function AST cyclomatic complexity, per-function fan-in + fan-out, coupling + cycle detection, structural PR diff with HTML reporter, coverage report with HTML reporter, one-call PR review (projscan_review)
|
|
4
|
+
"version": "1.8.0",
|
|
5
|
+
"description": "Agent-first code intelligence. MCP server (2025-03-26) with AST parsing for JavaScript, TypeScript, Python, Go, Java, Ruby, Rust, PHP, C#, Kotlin, Swift, and C++; code graph, file + per-function AST cyclomatic complexity, per-function fan-in + fan-out, coupling + cycle detection, structural PR diff with HTML reporter, coverage report with HTML reporter, one-call PR review (projscan_review) and long-running PR-watch mode (projscan_review_watch), rule-driven fix suggestions + mechanical apply layer with rollback (projscan_apply_fix, projscan_fix_suggest, projscan_explain_issue), source-to-sink taint analysis (projscan_taint) with truncation reporting, transitive blast-radius analysis with cross-repo mode (projscan_impact for files and symbols), cross-repo workspace registration + intelligence (projscan_workspace_graph), per-function semantic search chunks (sub-file embeddings), per-rule confidence + cost-summary analytics (projscan_cost_summary), monorepo workspace awareness with cross-package import policy + per-package dependencies / outdated / audit, BM25 + optional semantic search, cursor pagination, progress notifications, context-budgeted output, and a stable-surface CI guard. CLI on the side.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "./dist/index.js",
|
|
8
8
|
"types": "./dist/index.d.ts",
|
|
@@ -87,6 +87,7 @@
|
|
|
87
87
|
"tree-sitter-cli": "^0.26.8",
|
|
88
88
|
"tree-sitter-cpp": "^0.23.4",
|
|
89
89
|
"tree-sitter-kotlin": "^0.3.8",
|
|
90
|
+
"tree-sitter-swift": "^0.7.1",
|
|
90
91
|
"typescript": "^5.6.0",
|
|
91
92
|
"typescript-eslint": "^8.57.0",
|
|
92
93
|
"vitest": "^2.1.0"
|