homegraph 1.6.1 → 1.6.2
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 +22 -0
- package/dist/bin/homegraph.js +2 -2
- package/dist/db/index.js +1 -0
- package/dist/db/migrations.d.ts +6 -1
- package/dist/db/migrations.js +26 -1
- package/dist/db/queries.d.ts +5 -0
- package/dist/db/queries.js +17 -7
- package/dist/db/schema.sql +4 -0
- package/dist/extraction/grammars.js +2 -1
- package/dist/extraction/languages/c-cpp.d.ts +8 -0
- package/dist/extraction/languages/c-cpp.js +44 -0
- package/dist/extraction/wasm-runtime-flags.d.ts +4 -0
- package/dist/extraction/wasm-runtime-flags.js +9 -0
- package/dist/index.js +7 -1
- package/dist/installer/targets/icode.d.ts +43 -0
- package/dist/installer/targets/icode.js +631 -0
- package/dist/installer/targets/registry.js +2 -0
- package/dist/installer/targets/types.d.ts +1 -1
- package/dist/mcp/evidence-rendering.js +1 -1
- package/dist/mcp/explore-repeat-guard.d.ts +19 -5
- package/dist/mcp/explore-repeat-guard.js +35 -14
- package/dist/mcp/explore-session-state.d.ts +5 -0
- package/dist/mcp/explore-session-state.js +1 -0
- package/dist/mcp/locate-contract.js +1 -1
- package/dist/mcp/server-instructions.d.ts +2 -2
- package/dist/mcp/server-instructions.js +10 -10
- package/dist/mcp/session.js +3 -2
- package/dist/mcp/tools.d.ts +21 -2
- package/dist/mcp/tools.js +109 -50
- package/dist/resolution/c-feature-variants.d.ts +40 -0
- package/dist/resolution/c-feature-variants.js +272 -0
- package/dist/resolution/cpp-macro-visibility.d.ts +21 -0
- package/dist/resolution/cpp-macro-visibility.js +393 -0
- package/dist/resolution/index.js +11 -0
- package/dist/resolution/name-matcher.js +49 -2
- package/dist/resolution/types.d.ts +8 -0
- package/dist/resolution/types.js +8 -0
- package/dist/sync/watcher.d.ts +30 -0
- package/dist/sync/watcher.js +45 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -10,6 +10,27 @@ and adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
10
10
|
## [Unreleased]
|
|
11
11
|
|
|
12
12
|
|
|
13
|
+
## [1.6.2] - 2026-10-19
|
|
14
|
+
|
|
15
|
+
### New Features
|
|
16
|
+
|
|
17
|
+
- **iCode support** in the installer. `homegraph install --target icode` wires the MCP server into iCode agent profiles (`~/.chrys/agents/` on macOS/Linux, `%APPDATA%\chrys\agents\` on Windows). The target is global-only. It edits existing profiles in place and, when the iCode runtime is found, writes shadow profiles for the built-in agents. If the runtime is missing, install still updates existing profiles and prints manual guidance. `HOMEGRAPH_ICODE_NO_BUILTINS=1` skips shadows. No instructions file is written (Spec 0057).
|
|
18
|
+
|
|
19
|
+
### Improvements
|
|
20
|
+
|
|
21
|
+
- `homegraph_explore` no longer stops after 2 calls on a long-lived MCP connection. Another explore within 10 seconds of the previous result is refused; a later call, including a different question, is allowed. The tool description, initialize instructions, and explore footer state that wait (Spec 0058).
|
|
22
|
+
- MCP initialize / `homegraph_explore` description: drop bash-first and "HomeGraph is optional" wording that conflicted with DevEco Code's graph-first product prompt; existing-code tasks open with `homegraph_explore` alone. Tool list, budgets, and evidence caveats unchanged.
|
|
23
|
+
- MCP under Bun skips the Node/V8 `--liftoff-only` relaunch (those flags do not apply), so product hosts can spawn `homegraph.js` with the host Bun binary (Spec 0052).
|
|
24
|
+
- MCP product hosts that prefix tools with the server name (e.g. DevEco Code) can set `HOMEGRAPH_MCP_SHORT_TOOL_NAMES=1` so tools/list exposes short names (`explore`, `project`) and tools/call still accepts both short and `homegraph_*` forms — avoiding a doubled `homegraph_homegraph_*` name after the host prefix. Unset by default; Cursor/Claude keep canonical `homegraph_*` names.
|
|
25
|
+
|
|
26
|
+
### Fixes
|
|
27
|
+
|
|
28
|
+
- C/C++: a call no longer binds another file's `static` function when a definition with external linkage exists. A C definition compiled only under a feature flag nothing in the project sets yields to the definition the default build compiles (Spec 0056).
|
|
29
|
+
- Windows: a file the daemon only read no longer shows up as edited. Watcher events whose size and modification time still match the index are ignored, so an NTFS last-access update does not mark the file pending sync (Spec 0055).
|
|
30
|
+
- C/C++: a header whose only C++ signal is `struct Derived : Base` is indexed as C++. A call that names a function-like macro visible at that line is not linked to a same-named function, and the include walk that decides this is bounded so a deep guard graph cannot blow the heap (Spec 0054).
|
|
31
|
+
- MCP `homegraph_explore` call budget shown to agents is **2** on every repo size, matching the session hard cap. Output sizing tiers are unchanged. Heuristic edges store `synthesized_by`, and ArkTS cross-file call cleanup deletes that channel by column instead of a JSON text match. Explore and Partial replies no longer tell the agent to call `homegraph_node`. Name search still tries FTS first, including Chinese literals (Spec 0053).
|
|
32
|
+
- MCP tools/list: when a session has no default project, `projectPath` is already marked `required` in the schema — its property description no longer says "Omit to use this session's default project", so agents are not told the field is both required and optional.
|
|
33
|
+
|
|
13
34
|
## [1.6.1] - 2026-09-28
|
|
14
35
|
|
|
15
36
|
### Improvements
|
|
@@ -283,3 +304,4 @@ and adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
283
304
|
[1.5.10]: https://github.com/fujiaxin-coder/homegraph/releases/tag/v1.5.10
|
|
284
305
|
[1.6.0]: https://github.com/fujiaxin-coder/homegraph/releases/tag/v1.6.0
|
|
285
306
|
[1.6.1]: https://github.com/fujiaxin-coder/homegraph/releases/tag/v1.6.1
|
|
307
|
+
[1.6.2]: https://github.com/fujiaxin-coder/homegraph/releases/tag/v1.6.2
|
package/dist/bin/homegraph.js
CHANGED
|
@@ -1917,7 +1917,7 @@ function main() {
|
|
|
1917
1917
|
*/
|
|
1918
1918
|
program
|
|
1919
1919
|
.command('install')
|
|
1920
|
-
.description('Install homegraph MCP server into one or more agents (Claude Code, Cursor, Codex CLI, opencode, DevEco Code, CodeBuddy, Hermes Agent)')
|
|
1920
|
+
.description('Install homegraph MCP server into one or more agents (Claude Code, Cursor, Codex CLI, opencode, DevEco Code, CodeBuddy, Hermes Agent, iCode)')
|
|
1921
1921
|
.option('-t, --target <ids>', 'Target agent(s): comma-separated ids, or "auto"|"all"|"none". Default: prompt')
|
|
1922
1922
|
.option('-l, --location <where>', 'Install location: "global" or "local". Default: prompt')
|
|
1923
1923
|
.option('-y, --yes', 'Non-interactive: defaults to --location=global --target=auto, auto-allow on')
|
|
@@ -1976,7 +1976,7 @@ function main() {
|
|
|
1976
1976
|
*/
|
|
1977
1977
|
program
|
|
1978
1978
|
.command('uninstall')
|
|
1979
|
-
.description('Remove homegraph from your agents (Claude Code, Cursor, Codex CLI, opencode, DevEco Code, CodeBuddy, Hermes Agent)')
|
|
1979
|
+
.description('Remove homegraph from your agents (Claude Code, Cursor, Codex CLI, opencode, DevEco Code, CodeBuddy, Hermes Agent, iCode)')
|
|
1980
1980
|
.option('-t, --target <ids>', 'Target agent(s): comma-separated ids, or "all". Default: all')
|
|
1981
1981
|
.option('-l, --location <where>', 'Uninstall location: "global" or "local". Default: prompt')
|
|
1982
1982
|
.option('-y, --yes', 'Non-interactive: defaults to --location=global --target=all')
|
package/dist/db/index.js
CHANGED
package/dist/db/migrations.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ import { SqliteDatabase } from './sqlite-adapter';
|
|
|
7
7
|
/**
|
|
8
8
|
* Current schema version
|
|
9
9
|
*/
|
|
10
|
-
export declare const CURRENT_SCHEMA_VERSION =
|
|
10
|
+
export declare const CURRENT_SCHEMA_VERSION = 12;
|
|
11
11
|
/**
|
|
12
12
|
* Migration definition
|
|
13
13
|
*/
|
|
@@ -16,6 +16,11 @@ interface Migration {
|
|
|
16
16
|
description: string;
|
|
17
17
|
up: (db: SqliteDatabase) => void;
|
|
18
18
|
}
|
|
19
|
+
/**
|
|
20
|
+
* Copy `metadata.synthesizedBy` onto `edges.synthesized_by` when the column is empty.
|
|
21
|
+
* Channel deletes read the column, not JSON text (Spec 0053).
|
|
22
|
+
*/
|
|
23
|
+
export declare function backfillEdgeSynthesizedBy(db: SqliteDatabase): void;
|
|
19
24
|
/**
|
|
20
25
|
* Get the current schema version from the database
|
|
21
26
|
*/
|
package/dist/db/migrations.js
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
8
|
exports.CURRENT_SCHEMA_VERSION = void 0;
|
|
9
|
+
exports.backfillEdgeSynthesizedBy = backfillEdgeSynthesizedBy;
|
|
9
10
|
exports.getCurrentVersion = getCurrentVersion;
|
|
10
11
|
exports.runMigrations = runMigrations;
|
|
11
12
|
exports.needsMigration = needsMigration;
|
|
@@ -14,7 +15,7 @@ exports.getMigrationHistory = getMigrationHistory;
|
|
|
14
15
|
/**
|
|
15
16
|
* Current schema version
|
|
16
17
|
*/
|
|
17
|
-
exports.CURRENT_SCHEMA_VERSION =
|
|
18
|
+
exports.CURRENT_SCHEMA_VERSION = 12;
|
|
18
19
|
/**
|
|
19
20
|
* All migrations in order
|
|
20
21
|
*
|
|
@@ -175,7 +176,31 @@ const migrations = [
|
|
|
175
176
|
`);
|
|
176
177
|
},
|
|
177
178
|
},
|
|
179
|
+
{
|
|
180
|
+
version: 12,
|
|
181
|
+
description: 'Add edges.synthesized_by and backfill from metadata.synthesizedBy (Spec 0053)',
|
|
182
|
+
up: (db) => {
|
|
183
|
+
const cols = db.prepare('PRAGMA table_info(edges)').all();
|
|
184
|
+
if (!cols.some((c) => c.name === 'synthesized_by')) {
|
|
185
|
+
db.exec('ALTER TABLE edges ADD COLUMN synthesized_by TEXT');
|
|
186
|
+
}
|
|
187
|
+
backfillEdgeSynthesizedBy(db);
|
|
188
|
+
db.exec('CREATE INDEX IF NOT EXISTS idx_edges_synthesized_by ON edges(synthesized_by) WHERE synthesized_by IS NOT NULL');
|
|
189
|
+
},
|
|
190
|
+
},
|
|
178
191
|
];
|
|
192
|
+
/**
|
|
193
|
+
* Copy `metadata.synthesizedBy` onto `edges.synthesized_by` when the column is empty.
|
|
194
|
+
* Channel deletes read the column, not JSON text (Spec 0053).
|
|
195
|
+
*/
|
|
196
|
+
function backfillEdgeSynthesizedBy(db) {
|
|
197
|
+
db.exec(`
|
|
198
|
+
UPDATE edges
|
|
199
|
+
SET synthesized_by = json_extract(metadata, '$.synthesizedBy')
|
|
200
|
+
WHERE (synthesized_by IS NULL OR synthesized_by = '')
|
|
201
|
+
AND json_extract(metadata, '$.synthesizedBy') IS NOT NULL
|
|
202
|
+
`);
|
|
203
|
+
}
|
|
179
204
|
/**
|
|
180
205
|
* Get the current schema version from the database
|
|
181
206
|
*/
|
package/dist/db/queries.d.ts
CHANGED
|
@@ -5,6 +5,11 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { SqliteDatabase } from './sqlite-adapter';
|
|
7
7
|
import { Node, Edge, FileRecord, UnresolvedReference, NodeKind, EdgeKind, Language, GraphStats, SearchOptions, SearchResult } from '../types';
|
|
8
|
+
/**
|
|
9
|
+
* Convert database row to Edge object
|
|
10
|
+
*/
|
|
11
|
+
/** Channel name stored on `edges.synthesized_by` (Spec 0053). */
|
|
12
|
+
export declare function edgeSynthesizedBy(edge: Edge): string | null;
|
|
8
13
|
/**
|
|
9
14
|
* Query builder for the knowledge graph database
|
|
10
15
|
*/
|
package/dist/db/queries.js
CHANGED
|
@@ -39,6 +39,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
39
39
|
})();
|
|
40
40
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
41
41
|
exports.QueryBuilder = void 0;
|
|
42
|
+
exports.edgeSynthesizedBy = edgeSynthesizedBy;
|
|
42
43
|
const fs = __importStar(require("fs"));
|
|
43
44
|
const path = __importStar(require("path"));
|
|
44
45
|
const utils_1 = require("../utils");
|
|
@@ -110,6 +111,11 @@ function rowToNode(row) {
|
|
|
110
111
|
/**
|
|
111
112
|
* Convert database row to Edge object
|
|
112
113
|
*/
|
|
114
|
+
/** Channel name stored on `edges.synthesized_by` (Spec 0053). */
|
|
115
|
+
function edgeSynthesizedBy(edge) {
|
|
116
|
+
const value = edge.metadata?.synthesizedBy;
|
|
117
|
+
return typeof value === 'string' && value.trim() ? value.trim() : null;
|
|
118
|
+
}
|
|
113
119
|
function rowToEdge(row) {
|
|
114
120
|
return {
|
|
115
121
|
source: row.source,
|
|
@@ -383,9 +389,10 @@ class QueryBuilder {
|
|
|
383
389
|
edge.line ?? null,
|
|
384
390
|
edge.column ?? null,
|
|
385
391
|
edge.provenance ?? null,
|
|
392
|
+
edgeSynthesizedBy(edge),
|
|
386
393
|
]);
|
|
387
394
|
}
|
|
388
|
-
this.runBatched('insertEdges', 'INSERT OR IGNORE INTO edges (source, target, kind, metadata, line, col, provenance) VALUES ', '(
|
|
395
|
+
this.runBatched('insertEdges', 'INSERT OR IGNORE INTO edges (source, target, kind, metadata, line, col, provenance, synthesized_by) VALUES ', '(?,?,?,?,?,?,?,?)', rows);
|
|
389
396
|
}
|
|
390
397
|
if (bundle.refs.length > 0)
|
|
391
398
|
this.insertUnresolvedRefsBatch(bundle.refs);
|
|
@@ -994,11 +1001,13 @@ class QueryBuilder {
|
|
|
994
1001
|
return [];
|
|
995
1002
|
return this.mergeOhosApiTextSearch(text, { kinds, languages, limit }, []);
|
|
996
1003
|
}
|
|
997
|
-
// First try FTS5 with prefix matching
|
|
1004
|
+
// First try FTS5 with prefix matching. Chinese literals (for example
|
|
1005
|
+
// string.json values in docstring) are real FTS tokens — do not skip them.
|
|
998
1006
|
let results = text
|
|
999
1007
|
? this.searchNodesFTS(text, { kinds, languages, limit, offset })
|
|
1000
1008
|
// Over-fetch by 5× when running filter-only (no text). The
|
|
1001
|
-
// post-scoring path:
|
|
1009
|
+
// post-scoring path: name: filters can be very selective, so
|
|
1010
|
+
// a smaller multiplier risks returning fewer than `limit`
|
|
1002
1011
|
// results despite the DB having plenty of matches.
|
|
1003
1012
|
: this.searchAllByFilters({ kinds, languages, limit: limit * 5 });
|
|
1004
1013
|
// If no FTS results, try LIKE-based substring search
|
|
@@ -1497,8 +1506,8 @@ class QueryBuilder {
|
|
|
1497
1506
|
insertEdge(edge) {
|
|
1498
1507
|
if (!this.stmts.insertEdge) {
|
|
1499
1508
|
this.stmts.insertEdge = this.db.prepare(`
|
|
1500
|
-
INSERT OR IGNORE INTO edges (source, target, kind, metadata, line, col, provenance)
|
|
1501
|
-
VALUES (@source, @target, @kind, @metadata, @line, @col, @provenance)
|
|
1509
|
+
INSERT OR IGNORE INTO edges (source, target, kind, metadata, line, col, provenance, synthesized_by)
|
|
1510
|
+
VALUES (@source, @target, @kind, @metadata, @line, @col, @provenance, @synthesizedBy)
|
|
1502
1511
|
`);
|
|
1503
1512
|
}
|
|
1504
1513
|
this.stmts.insertEdge.run({
|
|
@@ -1509,6 +1518,7 @@ class QueryBuilder {
|
|
|
1509
1518
|
line: edge.line ?? null,
|
|
1510
1519
|
col: edge.column ?? null,
|
|
1511
1520
|
provenance: edge.provenance ?? null,
|
|
1521
|
+
synthesizedBy: edgeSynthesizedBy(edge),
|
|
1512
1522
|
});
|
|
1513
1523
|
}
|
|
1514
1524
|
/**
|
|
@@ -1713,8 +1723,8 @@ class QueryBuilder {
|
|
|
1713
1723
|
.prepare(`DELETE FROM edges
|
|
1714
1724
|
WHERE kind = 'calls'
|
|
1715
1725
|
AND provenance = 'heuristic'
|
|
1716
|
-
AND
|
|
1717
|
-
AND metadata
|
|
1726
|
+
AND synthesized_by = 'arkanalyzer'
|
|
1727
|
+
AND json_extract(metadata, '$.sourceFile') IS NOT NULL`)
|
|
1718
1728
|
.run();
|
|
1719
1729
|
return result.changes;
|
|
1720
1730
|
}
|
package/dist/db/schema.sql
CHANGED
|
@@ -52,6 +52,9 @@ CREATE TABLE IF NOT EXISTS edges (
|
|
|
52
52
|
line INTEGER,
|
|
53
53
|
col INTEGER,
|
|
54
54
|
provenance TEXT DEFAULT NULL,
|
|
55
|
+
-- Channel of a heuristic edge (`metadata.synthesizedBy`). Written on insert
|
|
56
|
+
-- so re-index can delete by channel without matching JSON text (Spec 0053).
|
|
57
|
+
synthesized_by TEXT,
|
|
55
58
|
FOREIGN KEY (source) REFERENCES nodes(id) ON DELETE CASCADE,
|
|
56
59
|
FOREIGN KEY (target) REFERENCES nodes(id) ON DELETE CASCADE
|
|
57
60
|
);
|
|
@@ -192,6 +195,7 @@ CREATE INDEX IF NOT EXISTS idx_unresolved_from_name ON unresolved_refs(from_node
|
|
|
192
195
|
CREATE INDEX IF NOT EXISTS idx_unresolved_status ON unresolved_refs(status);
|
|
193
196
|
CREATE INDEX IF NOT EXISTS idx_unresolved_failed_tail ON unresolved_refs(name_tail) WHERE status = 'failed';
|
|
194
197
|
CREATE INDEX IF NOT EXISTS idx_edges_provenance ON edges(provenance);
|
|
198
|
+
CREATE INDEX IF NOT EXISTS idx_edges_synthesized_by ON edges(synthesized_by) WHERE synthesized_by IS NOT NULL;
|
|
195
199
|
|
|
196
200
|
-- Project metadata for version/provenance tracking
|
|
197
201
|
CREATE TABLE IF NOT EXISTS project_metadata (
|
|
@@ -529,7 +529,8 @@ function looksLikeCpp(source) {
|
|
|
529
529
|
// routed through the C extractor (which extracts no classes), and its class
|
|
530
530
|
// definition silently vanishes. The two-token shape (`<KW> <MACRO> <Name>`
|
|
531
531
|
// before a `[:{]`) never occurs in valid C, so this can't misclassify C headers.
|
|
532
|
-
|
|
532
|
+
// `struct Derived : Base` is C++. A plain `struct Point {` stays C.
|
|
533
|
+
return /\bnamespace\b|\bclass\s+\w+\s*[:{]|\bstruct\s+\w+\s*:|\b(?:class|struct)\s+[A-Z][A-Z0-9_]+\s+\w+\s*(?:final\s*)?[:{]|\btemplate\s*<|\b(?:public|private|protected)\s*:|\bvirtual\b|\busing\s+(?:namespace\b|\w+\s*=)/.test(sample);
|
|
533
534
|
}
|
|
534
535
|
/**
|
|
535
536
|
* Heuristic: does a .h file contain Objective-C constructs?
|
|
@@ -102,6 +102,14 @@ export declare function blankMetalAttributes(source: string): string;
|
|
|
102
102
|
* ALL-CAPS call that isn't markup only loses that one annotation, never a whole
|
|
103
103
|
* class.
|
|
104
104
|
*/
|
|
105
|
+
/**
|
|
106
|
+
* Mask C++ raw string literals (`R"delim(...)delim"`) so later blankers do not
|
|
107
|
+
* treat their contents as code. Offsets stay aligned with the original source.
|
|
108
|
+
*/
|
|
109
|
+
export declare function maskCppRawStrings(source: string): {
|
|
110
|
+
source: string;
|
|
111
|
+
restore: (blanked: string) => string;
|
|
112
|
+
};
|
|
105
113
|
export declare function blankCppAnnotationMacroCalls(source: string): string;
|
|
106
114
|
export declare function blankCppApiPrefixMacros(source: string): string;
|
|
107
115
|
export declare function blankCppInlineAnnotationMacros(source: string): string;
|
|
@@ -7,6 +7,7 @@ exports.blankCppExportMacros = blankCppExportMacros;
|
|
|
7
7
|
exports.blankCppInlineMacros = blankCppInlineMacros;
|
|
8
8
|
exports.recoverMangledCppName = recoverMangledCppName;
|
|
9
9
|
exports.blankMetalAttributes = blankMetalAttributes;
|
|
10
|
+
exports.maskCppRawStrings = maskCppRawStrings;
|
|
10
11
|
exports.blankCppAnnotationMacroCalls = blankCppAnnotationMacroCalls;
|
|
11
12
|
exports.blankCppApiPrefixMacros = blankCppApiPrefixMacros;
|
|
12
13
|
exports.blankCppInlineAnnotationMacros = blankCppInlineAnnotationMacros;
|
|
@@ -493,6 +494,49 @@ function blankMetalAttributes(source) {
|
|
|
493
494
|
* ALL-CAPS call that isn't markup only loses that one annotation, never a whole
|
|
494
495
|
* class.
|
|
495
496
|
*/
|
|
497
|
+
/**
|
|
498
|
+
* Mask C++ raw string literals (`R"delim(...)delim"`) so later blankers do not
|
|
499
|
+
* treat their contents as code. Offsets stay aligned with the original source.
|
|
500
|
+
*/
|
|
501
|
+
function maskCppRawStrings(source) {
|
|
502
|
+
const unchanged = { source, restore: (blanked) => blanked };
|
|
503
|
+
if (source.indexOf('R"') === -1)
|
|
504
|
+
return unchanged;
|
|
505
|
+
const re = /\/\/[^\r\n]*|\/\*[\s\S]*?(?:\*\/|$)|\b(?:u8|[LuU])?R"([^ \t\v\f\r\n()\\]{0,16})\(|"(?:\\[\s\S]|[^"\\])*(?:"|$)|(?<!\w)(?:u8|[LuU])?'(?:\\[\s\S]|[^'\\])*(?:'|$)/g;
|
|
506
|
+
const spans = [];
|
|
507
|
+
const parts = [];
|
|
508
|
+
let last = 0;
|
|
509
|
+
let m;
|
|
510
|
+
while ((m = re.exec(source)) !== null) {
|
|
511
|
+
if (m[1] === undefined)
|
|
512
|
+
continue;
|
|
513
|
+
const closer = `)${m[1]}"`;
|
|
514
|
+
const close = source.indexOf(closer, re.lastIndex);
|
|
515
|
+
const end = close < 0 ? source.length : close + closer.length;
|
|
516
|
+
spans.push({ start: m.index, end });
|
|
517
|
+
parts.push(source.slice(last, m.index), source.slice(m.index, end).replace(/[^\r\n]/g, '\0'));
|
|
518
|
+
last = re.lastIndex = end;
|
|
519
|
+
}
|
|
520
|
+
if (spans.length === 0)
|
|
521
|
+
return unchanged;
|
|
522
|
+
parts.push(source.slice(last));
|
|
523
|
+
const masked = parts.join('');
|
|
524
|
+
return {
|
|
525
|
+
source: masked,
|
|
526
|
+
restore(blanked) {
|
|
527
|
+
if (blanked === masked || blanked.length !== source.length)
|
|
528
|
+
return source;
|
|
529
|
+
const chars = blanked.split('');
|
|
530
|
+
for (const { start, end } of spans) {
|
|
531
|
+
for (let i = start; i < end; i++) {
|
|
532
|
+
if (chars[i] === '\0')
|
|
533
|
+
chars[i] = source[i];
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
return chars.join('');
|
|
537
|
+
},
|
|
538
|
+
};
|
|
539
|
+
}
|
|
496
540
|
function blankCppAnnotationMacroCalls(source) {
|
|
497
541
|
if (!/^[ \t]*[A-Z][A-Z0-9_]{2,}\s*\(/m.test(source))
|
|
498
542
|
return source;
|
|
@@ -44,5 +44,9 @@ export declare function buildRelaunchArgv(scriptPath: string, scriptArgs: readon
|
|
|
44
44
|
* On spawn failure, returns so the caller runs in-process anyway — risking the
|
|
45
45
|
* OOM is still better than refusing to start.
|
|
46
46
|
*/
|
|
47
|
+
/** Bun is not V8 — `--liftoff-only` / `--max-old-space-size` relaunch does not apply. */
|
|
48
|
+
export declare function isBunRuntime(g?: {
|
|
49
|
+
Bun?: unknown;
|
|
50
|
+
}): boolean;
|
|
47
51
|
export declare function relaunchWithWasmRuntimeFlagsIfNeeded(scriptPath: string): void;
|
|
48
52
|
//# sourceMappingURL=wasm-runtime-flags.d.ts.map
|
|
@@ -6,6 +6,7 @@ exports.maxOldSpaceSizeFlag = maxOldSpaceSizeFlag;
|
|
|
6
6
|
exports.processHasWasmRuntimeFlags = processHasWasmRuntimeFlags;
|
|
7
7
|
exports.processHasRequiredRuntimeFlags = processHasRequiredRuntimeFlags;
|
|
8
8
|
exports.buildRelaunchArgv = buildRelaunchArgv;
|
|
9
|
+
exports.isBunRuntime = isBunRuntime;
|
|
9
10
|
exports.relaunchWithWasmRuntimeFlagsIfNeeded = relaunchWithWasmRuntimeFlagsIfNeeded;
|
|
10
11
|
/**
|
|
11
12
|
* WASM runtime flags — workaround for the V8 turboshaft WASM Zone OOM.
|
|
@@ -134,6 +135,10 @@ function buildRelaunchArgv(scriptPath, scriptArgs, execArgv = process.execArgv)
|
|
|
134
135
|
* On spawn failure, returns so the caller runs in-process anyway — risking the
|
|
135
136
|
* OOM is still better than refusing to start.
|
|
136
137
|
*/
|
|
138
|
+
/** Bun is not V8 — `--liftoff-only` / `--max-old-space-size` relaunch does not apply. */
|
|
139
|
+
function isBunRuntime(g = globalThis) {
|
|
140
|
+
return typeof g.Bun !== 'undefined';
|
|
141
|
+
}
|
|
137
142
|
function relaunchWithWasmRuntimeFlagsIfNeeded(scriptPath) {
|
|
138
143
|
if (processHasRequiredRuntimeFlags())
|
|
139
144
|
return;
|
|
@@ -141,6 +146,10 @@ function relaunchWithWasmRuntimeFlagsIfNeeded(scriptPath) {
|
|
|
141
146
|
return;
|
|
142
147
|
if (process.env.HOMEGRAPH_NO_RELAUNCH)
|
|
143
148
|
return;
|
|
149
|
+
// Product hosts (e.g. DevEco Code) spawn MCP under Bun; V8 flags would be
|
|
150
|
+
// ignored or break relaunch. Stay in-process.
|
|
151
|
+
if (isBunRuntime())
|
|
152
|
+
return;
|
|
144
153
|
const argv = buildRelaunchArgv(scriptPath, process.argv.slice(2));
|
|
145
154
|
const result = (0, child_process_1.spawnSync)(process.execPath, argv, {
|
|
146
155
|
stdio: 'inherit',
|
package/dist/index.js
CHANGED
|
@@ -854,7 +854,13 @@ class HomeGraph {
|
|
|
854
854
|
}
|
|
855
855
|
const filesChanged = result.filesAdded + result.filesModified + result.filesRemoved;
|
|
856
856
|
return { filesChanged, durationMs: result.durationMs };
|
|
857
|
-
},
|
|
857
|
+
}, {
|
|
858
|
+
...options,
|
|
859
|
+
indexedFingerprint: options.indexedFingerprint ?? ((rel) => {
|
|
860
|
+
const rec = this.getFile(rel);
|
|
861
|
+
return rec ? { size: rec.size, modifiedAt: rec.modifiedAt } : null;
|
|
862
|
+
}),
|
|
863
|
+
});
|
|
858
864
|
return this.watcher.start();
|
|
859
865
|
}
|
|
860
866
|
/**
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* iCode target.
|
|
3
|
+
*
|
|
4
|
+
* iCode (product name) ships as the Python package `chrys`; agent profiles
|
|
5
|
+
* are individual YAML files, one per profile, under `~/.chrys/agents/`
|
|
6
|
+
* (macOS/Linux) or `%APPDATA%\chrys\agents\` (Windows). Each profile is a
|
|
7
|
+
* complete agent definition carrying a `tools.mcp` list of MCP server
|
|
8
|
+
* configs.
|
|
9
|
+
*
|
|
10
|
+
* iCode has NO project-local config concept — this target is global-only.
|
|
11
|
+
*
|
|
12
|
+
* Install (synchronous, non-interactive — no per-profile prompt):
|
|
13
|
+
* 1. Every EXISTING user profile under `~/.chrys/agents/*.yaml|yml` gets
|
|
14
|
+
* the homegraph MCP entry injected in place — a surgical line edit
|
|
15
|
+
* that preserves sibling MCP servers and every other section.
|
|
16
|
+
* 2. Built-in agents (Code / QA / Explore / General) are discovered from
|
|
17
|
+
* the installed iCode runtime
|
|
18
|
+
* (`.../site-packages/chrys/service/profiles/agents/builtins/`). A
|
|
19
|
+
* built-in with no user profile of the same name gets a "shadow"
|
|
20
|
+
* profile written to `~/.chrys/agents/<name>.yaml`: the built-in's
|
|
21
|
+
* FULL content plus the homegraph entry. (iCode's own override rule:
|
|
22
|
+
* a user profile with a built-in's name REPLACES the built-in
|
|
23
|
+
* entirely, so the copy must be complete.)
|
|
24
|
+
* If the runtime can't be located, install degrades to editing
|
|
25
|
+
* existing profiles only and returns manual guidance in `notes` — it
|
|
26
|
+
* never throws.
|
|
27
|
+
*
|
|
28
|
+
* Uninstall strips the homegraph entry from every user profile that
|
|
29
|
+
* carries it (shadow files are left as plain built-in copies), matching
|
|
30
|
+
* the other targets' "remove only what install wrote" contract.
|
|
31
|
+
*
|
|
32
|
+
* No instructions file is written (#529/#704) — guidance ships in the MCP
|
|
33
|
+
* `initialize` response, which iCode injects into system reminders by
|
|
34
|
+
* default (`expose_instructions: true`).
|
|
35
|
+
*
|
|
36
|
+
* NOTE: unlike the codegraph fork, this target must NOT suppress the
|
|
37
|
+
* "install the CLI on PATH" step in `src/installer/index.ts` — the MCP
|
|
38
|
+
* command is the `homegraph` Node CLI, which iCode (a Python app) does not
|
|
39
|
+
* bundle.
|
|
40
|
+
*/
|
|
41
|
+
import { AgentTarget } from './types';
|
|
42
|
+
export declare const icodeTarget: AgentTarget;
|
|
43
|
+
//# sourceMappingURL=icode.d.ts.map
|