@quolu/lattice 0.60.3 → 0.60.5
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/LICENSE +147 -147
- package/README.ja.md +387 -387
- package/README.md +291 -291
- package/bin/lattice-dashboard.mjs +7 -3
- package/bin/lattice-mcp.mjs +0 -0
- package/bin/lattice-scripted-adapter.mjs +0 -0
- package/bin/lattice-scripted-worker.mjs +0 -0
- package/bin/lattice-work-order-adapter.mjs +0 -0
- package/bin/lattice.mjs +2 -4
- package/docs/bridge-setup.md +239 -239
- package/docs/schemas/lattice.executor_packet.v1.schema.json +57 -57
- package/docs/schemas/lattice.executor_receipt.v1.schema.json +66 -66
- package/docs/schemas/lattice.phase_todo_revision.v3.schema.json +360 -360
- package/docs/schemas/lattice.plan_create_input.v1.schema.json +56 -56
- package/docs/schemas/lattice.plan_create_input.v2.schema.json +72 -72
- package/docs/schemas/lattice.plan_create_input.v3.schema.json +81 -81
- package/docs/schemas/lattice.plan_create_input.v4.schema.json +85 -85
- package/docs/schemas/lattice.plan_scope_review.v1.schema.json +55 -55
- package/docs/schemas/lattice.run_request.v1.schema.json +238 -238
- package/docs/schemas/lattice.runtime_adapter_capabilities.v2.schema.json +55 -55
- package/docs/schemas/lattice.runtime_adapter_registration_input.v1.schema.json +78 -78
- package/docs/schemas/lattice.runtime_adapter_registration_input.v2.schema.json +86 -86
- package/docs/schemas/lattice.todo_extraction.v2.schema.json +298 -298
- package/docs/schemas/lattice.todo_extraction.v3.schema.json +150 -150
- package/docs/schemas/lattice.todo_extraction.v4.schema.json +161 -161
- package/docs/schemas/lattice.todo_revision.v2.schema.json +260 -260
- package/docs/schemas/lattice.todo_revision_set.v3.schema.json +363 -363
- package/docs/schemas/lattice.todo_structure_binding.v1.schema.json +47 -47
- package/docs/schemas/lattice.todo_structure_realization.v1.schema.json +55 -55
- package/docs/schemas/lattice.todo_structure_set.v1.schema.json +264 -264
- package/package.json +109 -108
- package/sensor/LICENSE +21 -21
- package/sensor/NOTICE +19 -19
- package/sensor/dist/bin/lattice-sensor.js +9 -9
- package/sensor/dist/bin/node-version-check.js +1 -1
- package/sensor/dist/bin/node-version-check.js.map +1 -1
- package/sensor/dist/db/index.js +24 -24
- package/sensor/dist/db/migrations.js +41 -41
- package/sensor/dist/db/queries.js +164 -164
- package/sensor/dist/db/schema.sql +205 -205
- package/sensor/dist/directory.js +5 -5
- package/sensor/dist/extraction/wasm/tree-sitter-c_sharp.wasm +0 -0
- package/sensor/dist/extraction/wasm/tree-sitter-cfml.wasm +0 -0
- package/sensor/dist/extraction/wasm/tree-sitter-cfquery.wasm +0 -0
- package/sensor/dist/extraction/wasm/tree-sitter-cfscript.wasm +0 -0
- package/sensor/dist/extraction/wasm/tree-sitter-cobol.wasm +0 -0
- package/sensor/dist/extraction/wasm/tree-sitter-erlang.wasm +0 -0
- package/sensor/dist/extraction/wasm/tree-sitter-go.wasm +0 -0
- package/sensor/dist/extraction/wasm/tree-sitter-java.wasm +0 -0
- package/sensor/dist/extraction/wasm/tree-sitter-javascript.wasm +0 -0
- package/sensor/dist/extraction/wasm/tree-sitter-nix.wasm +0 -0
- package/sensor/dist/extraction/wasm/tree-sitter-pascal.wasm +0 -0
- package/sensor/dist/extraction/wasm/tree-sitter-python.wasm +0 -0
- package/sensor/dist/extraction/wasm/tree-sitter-tsx.wasm +0 -0
- package/sensor/dist/extraction/wasm/tree-sitter-typescript.wasm +0 -0
- package/sensor/dist/extraction/wasm/tree-sitter-vbnet.wasm +0 -0
- package/sensor/dist/mcp/liveness-watchdog.js +53 -53
- package/sensor/dist/mcp/server-instructions.js +95 -95
- package/sensor/dist/sync/worktree.js +1 -1
- package/sensor/dist/sync/worktree.js.map +1 -1
- package/sensor/package.json +56 -56
- package/src/bridge-daemon.mjs +11 -3
- package/src/bridge-hub-landing.mjs +1 -1
- package/src/runtime-cli.mjs +7 -0
- package/src/runtime-managed-supervisor.mjs +9 -1
- package/src/sensor-node-runtime.mjs +3 -3
- package/src/todo-cli.mjs +5 -4
- package/src/todo-dashboard-registry.mjs +32 -12
- package/src/todo-gantt-live.mjs +18 -4
- package/src/todo-store-git-transaction.mjs +1 -1
- package/src/todo-store.mjs +128 -20
|
@@ -18,79 +18,79 @@ exports.SERVER_INSTRUCTIONS_NO_ROOT_INDEX = exports.SERVER_INSTRUCTIONS = void 0
|
|
|
18
18
|
* burn tokens. ADR 0049 / 0059 require the eight compatibility tools to remain
|
|
19
19
|
* visible by default; provider identity is Lattice regardless of their names.
|
|
20
20
|
*/
|
|
21
|
-
exports.SERVER_INSTRUCTIONS = `# Lattice sensor — code intelligence over an indexed knowledge graph
|
|
22
|
-
|
|
23
|
-
Provider identity: lattice. The lattice_sensor_* names below are compatibility tool names served by Lattice's own bundled sensor; they do not call or require the independent Lattice sensor product.
|
|
24
|
-
|
|
25
|
-
Lattice sensor is a SQLite knowledge graph of every symbol, edge, and file in
|
|
26
|
-
the workspace — pre-computed structure you would otherwise re-derive by
|
|
27
|
-
reading files (cached intelligence: thousands of parse/trace decisions you
|
|
28
|
-
don't pay to re-reason each run). Reads are sub-millisecond; the index lags
|
|
29
|
-
writes by ~1s through the file watcher. Reach for it BEFORE *and* while
|
|
30
|
-
writing or editing code — not just for questions: one call returns the
|
|
31
|
-
verbatim source PLUS who calls it and what it affects, so you edit with the
|
|
32
|
-
blast radius in view. More accurate context, in far fewer tokens and
|
|
33
|
-
round-trips than reading files yourself.
|
|
34
|
-
|
|
35
|
-
## One tool: lattice_sensor_explore — use it instead of reading files
|
|
36
|
-
|
|
37
|
-
There is a single tool, \`lattice_sensor_explore\`, and it is Read-equivalent. It
|
|
38
|
-
takes either a natural-language question or a bag of symbol/file names and
|
|
39
|
-
returns the **verbatim, line-numbered source** of the relevant symbols
|
|
40
|
-
grouped by file — the same \`<n>\\t<line>\` shape \`Read\` gives you, safe to
|
|
41
|
-
\`Edit\` from — PLUS the call path among them (including dynamic-dispatch hops
|
|
42
|
-
like callbacks, React re-render, and JSX children that grep can't follow) and
|
|
43
|
-
a blast-radius summary of what depends on them.
|
|
44
|
-
|
|
45
|
-
Whether you're answering "how does X work" or implementing a change (fixing a
|
|
46
|
-
bug, adding a feature), call \`lattice_sensor_explore\` before you Read. ONE call
|
|
47
|
-
usually answers the whole question. Lattice sensor IS the pre-built search index —
|
|
48
|
-
so running your own grep + read loop, or delegating the lookup to a separate
|
|
49
|
-
file-reading sub-task/agent, repeats work lattice sensor already did and costs more
|
|
50
|
-
for the same answer. A direct lattice sensor answer is typically one to a few
|
|
51
|
-
calls; a grep/read exploration is dozens.
|
|
52
|
-
|
|
53
|
-
## How to query
|
|
54
|
-
|
|
55
|
-
- **Almost any question — "how does X work", architecture, a bug, "what/where is X", or surveying an area** → \`lattice_sensor_explore\` with a natural-language question or the relevant names. ONE capped call returns the verbatim source grouped by file; most often the ONLY call you need.
|
|
56
|
-
- **"How does X reach/become Y? / the flow / the path from X to Y"** → \`lattice_sensor_explore\`, naming the symbols that span the flow (e.g. \`mutateElement renderScene\`) — it surfaces the call path among them, riding dynamic-dispatch hops, and returns their source.
|
|
57
|
-
- **Reading or editing a file/symbol you can name** → put its name or file path in the \`lattice_sensor_explore\` query — it returns that current line-numbered source (safe to \`Edit\` from) with the call path and blast radius attached, so you don't Read it separately. For an overloaded name it returns every matching definition's body in one call.
|
|
58
|
-
- **Need more?** Call \`lattice_sensor_explore\` again with more specific names — treat the source it returns as already Read.
|
|
59
|
-
|
|
60
|
-
## Anti-patterns
|
|
61
|
-
|
|
62
|
-
- **Trust lattice sensor's results — don't re-verify them with grep.** They come from a full AST parse; re-checking with grep is slower, less accurate, and wastes context.
|
|
63
|
-
- **Don't grep or Read first** to find or understand indexed code — ONE \`lattice_sensor_explore\` returns the relevant symbols' source together in a single round-trip. Reach for raw \`Read\`/\`Grep\` only to confirm a specific detail lattice sensor didn't cover, or for what lattice sensor doesn't index (configs, docs).
|
|
64
|
-
- **Don't reconstruct a flow by hand** — name the endpoints in one \`lattice_sensor_explore\` and it surfaces the path between them, dynamic-dispatch hops included.
|
|
65
|
-
- **After editing, check the staleness banner.** When a tool response starts with "⚠️ Some files referenced below were edited since the last index sync…", the listed files are pending re-index — Read those specific files for accurate content. Every file NOT in that banner is fresh, so still trust lattice sensor. A different, rarer banner — "⚠️ LatticeSensor auto-sync is DISABLED…" — means live watching stopped entirely (the whole index is frozen, not just a few files); until it's resolved, Read files directly to confirm anything that may have changed.
|
|
66
|
-
- **A file flagged "⚠ changed on disk after the last index sync" drifted from its index** (most common on projects queried via \`projectPath\`, which have no live watcher). LatticeSensor never serves a possibly-mis-sliced body from such a file — it either shows the file's full CURRENT source (trust it as a Read) or omits the source with this flag. When the source was omitted, Read that specific file; line numbers referencing it elsewhere in the response may be shifted until that project's next sync. All unflagged files remain trustworthy.
|
|
67
|
-
|
|
68
|
-
## Limitations
|
|
69
|
-
|
|
70
|
-
- If a project isn't indexed (no \`.lattice/sensor/\`), decide whether building the index will reduce total investigation time and model tokens for the current or expected work. When workspace writes and shell execution are allowed, you may run \`lattice sensor init <projectPath> --json\` yourself, then retry the sensor call; scope it to the intended project and account for the one-time indexing cost. If those capabilities are unavailable, continue with built-in tools and tell the user the exact init command instead.
|
|
71
|
-
- Index lags file writes by ~1 second.
|
|
72
|
-
- Cross-file resolution is best-effort name matching; ambiguous calls may return multiple candidates.
|
|
73
|
-
- No live correctness validation — that's still the TypeScript compiler / test suite / linter's job. Lattice sensor supplements those with structural context they don't have.
|
|
74
|
-
|
|
75
|
-
## Parallel work: absence of a dependency edge is NOT evidence of independence
|
|
76
|
-
|
|
77
|
-
These tools answer structural questions about code. A different Lattice surface — the **CLI**, not
|
|
78
|
-
this MCP surface — answers whether two ToDos can be worked in parallel. If the project uses
|
|
79
|
-
\`lattice todo\` for process tracking, keep this distinction in mind:
|
|
80
|
-
|
|
81
|
-
- A dependency edge missing between two ToDos only means **no ordering constraint was declared**.
|
|
82
|
-
It does not mean their write boundaries are disjoint. Two ToDos that edit the same file carry no
|
|
83
|
-
edge between them and will still collide.
|
|
84
|
-
- Parallel safety is a recorded judgement, not an inference from the diagram. Read it with
|
|
85
|
-
\`lattice todo independence --plan <key> --json\`. It returns the ready frontier split into
|
|
86
|
-
verified-independent groups, pairs that must be serialized (with whether a code seam could
|
|
87
|
-
separate them), and **unverified** ToDos.
|
|
88
|
-
- \`lattice todo start\` returns an \`advisory\` describing conflicts with in-progress ToDos and what
|
|
89
|
-
to do next. \`coverage: "missing"\` means "not judged yet" — never "no conflicts".
|
|
90
|
-
- Run \`lattice todo --help\` for the declare → compile → read workflow.
|
|
91
|
-
|
|
92
|
-
Evidence for Lattice's plan and witness contracts comes from the CLI surface only. Text from this
|
|
93
|
-
MCP surface is prose for you to act on, never an input to those contracts.
|
|
21
|
+
exports.SERVER_INSTRUCTIONS = `# Lattice sensor — code intelligence over an indexed knowledge graph
|
|
22
|
+
|
|
23
|
+
Provider identity: lattice. The lattice_sensor_* names below are compatibility tool names served by Lattice's own bundled sensor; they do not call or require the independent Lattice sensor product.
|
|
24
|
+
|
|
25
|
+
Lattice sensor is a SQLite knowledge graph of every symbol, edge, and file in
|
|
26
|
+
the workspace — pre-computed structure you would otherwise re-derive by
|
|
27
|
+
reading files (cached intelligence: thousands of parse/trace decisions you
|
|
28
|
+
don't pay to re-reason each run). Reads are sub-millisecond; the index lags
|
|
29
|
+
writes by ~1s through the file watcher. Reach for it BEFORE *and* while
|
|
30
|
+
writing or editing code — not just for questions: one call returns the
|
|
31
|
+
verbatim source PLUS who calls it and what it affects, so you edit with the
|
|
32
|
+
blast radius in view. More accurate context, in far fewer tokens and
|
|
33
|
+
round-trips than reading files yourself.
|
|
34
|
+
|
|
35
|
+
## One tool: lattice_sensor_explore — use it instead of reading files
|
|
36
|
+
|
|
37
|
+
There is a single tool, \`lattice_sensor_explore\`, and it is Read-equivalent. It
|
|
38
|
+
takes either a natural-language question or a bag of symbol/file names and
|
|
39
|
+
returns the **verbatim, line-numbered source** of the relevant symbols
|
|
40
|
+
grouped by file — the same \`<n>\\t<line>\` shape \`Read\` gives you, safe to
|
|
41
|
+
\`Edit\` from — PLUS the call path among them (including dynamic-dispatch hops
|
|
42
|
+
like callbacks, React re-render, and JSX children that grep can't follow) and
|
|
43
|
+
a blast-radius summary of what depends on them.
|
|
44
|
+
|
|
45
|
+
Whether you're answering "how does X work" or implementing a change (fixing a
|
|
46
|
+
bug, adding a feature), call \`lattice_sensor_explore\` before you Read. ONE call
|
|
47
|
+
usually answers the whole question. Lattice sensor IS the pre-built search index —
|
|
48
|
+
so running your own grep + read loop, or delegating the lookup to a separate
|
|
49
|
+
file-reading sub-task/agent, repeats work lattice sensor already did and costs more
|
|
50
|
+
for the same answer. A direct lattice sensor answer is typically one to a few
|
|
51
|
+
calls; a grep/read exploration is dozens.
|
|
52
|
+
|
|
53
|
+
## How to query
|
|
54
|
+
|
|
55
|
+
- **Almost any question — "how does X work", architecture, a bug, "what/where is X", or surveying an area** → \`lattice_sensor_explore\` with a natural-language question or the relevant names. ONE capped call returns the verbatim source grouped by file; most often the ONLY call you need.
|
|
56
|
+
- **"How does X reach/become Y? / the flow / the path from X to Y"** → \`lattice_sensor_explore\`, naming the symbols that span the flow (e.g. \`mutateElement renderScene\`) — it surfaces the call path among them, riding dynamic-dispatch hops, and returns their source.
|
|
57
|
+
- **Reading or editing a file/symbol you can name** → put its name or file path in the \`lattice_sensor_explore\` query — it returns that current line-numbered source (safe to \`Edit\` from) with the call path and blast radius attached, so you don't Read it separately. For an overloaded name it returns every matching definition's body in one call.
|
|
58
|
+
- **Need more?** Call \`lattice_sensor_explore\` again with more specific names — treat the source it returns as already Read.
|
|
59
|
+
|
|
60
|
+
## Anti-patterns
|
|
61
|
+
|
|
62
|
+
- **Trust lattice sensor's results — don't re-verify them with grep.** They come from a full AST parse; re-checking with grep is slower, less accurate, and wastes context.
|
|
63
|
+
- **Don't grep or Read first** to find or understand indexed code — ONE \`lattice_sensor_explore\` returns the relevant symbols' source together in a single round-trip. Reach for raw \`Read\`/\`Grep\` only to confirm a specific detail lattice sensor didn't cover, or for what lattice sensor doesn't index (configs, docs).
|
|
64
|
+
- **Don't reconstruct a flow by hand** — name the endpoints in one \`lattice_sensor_explore\` and it surfaces the path between them, dynamic-dispatch hops included.
|
|
65
|
+
- **After editing, check the staleness banner.** When a tool response starts with "⚠️ Some files referenced below were edited since the last index sync…", the listed files are pending re-index — Read those specific files for accurate content. Every file NOT in that banner is fresh, so still trust lattice sensor. A different, rarer banner — "⚠️ LatticeSensor auto-sync is DISABLED…" — means live watching stopped entirely (the whole index is frozen, not just a few files); until it's resolved, Read files directly to confirm anything that may have changed.
|
|
66
|
+
- **A file flagged "⚠ changed on disk after the last index sync" drifted from its index** (most common on projects queried via \`projectPath\`, which have no live watcher). LatticeSensor never serves a possibly-mis-sliced body from such a file — it either shows the file's full CURRENT source (trust it as a Read) or omits the source with this flag. When the source was omitted, Read that specific file; line numbers referencing it elsewhere in the response may be shifted until that project's next sync. All unflagged files remain trustworthy.
|
|
67
|
+
|
|
68
|
+
## Limitations
|
|
69
|
+
|
|
70
|
+
- If a project isn't indexed (no \`.lattice/sensor/\`), decide whether building the index will reduce total investigation time and model tokens for the current or expected work. When workspace writes and shell execution are allowed, you may run \`lattice sensor init <projectPath> --json\` yourself, then retry the sensor call; scope it to the intended project and account for the one-time indexing cost. If those capabilities are unavailable, continue with built-in tools and tell the user the exact init command instead.
|
|
71
|
+
- Index lags file writes by ~1 second.
|
|
72
|
+
- Cross-file resolution is best-effort name matching; ambiguous calls may return multiple candidates.
|
|
73
|
+
- No live correctness validation — that's still the TypeScript compiler / test suite / linter's job. Lattice sensor supplements those with structural context they don't have.
|
|
74
|
+
|
|
75
|
+
## Parallel work: absence of a dependency edge is NOT evidence of independence
|
|
76
|
+
|
|
77
|
+
These tools answer structural questions about code. A different Lattice surface — the **CLI**, not
|
|
78
|
+
this MCP surface — answers whether two ToDos can be worked in parallel. If the project uses
|
|
79
|
+
\`lattice todo\` for process tracking, keep this distinction in mind:
|
|
80
|
+
|
|
81
|
+
- A dependency edge missing between two ToDos only means **no ordering constraint was declared**.
|
|
82
|
+
It does not mean their write boundaries are disjoint. Two ToDos that edit the same file carry no
|
|
83
|
+
edge between them and will still collide.
|
|
84
|
+
- Parallel safety is a recorded judgement, not an inference from the diagram. Read it with
|
|
85
|
+
\`lattice todo independence --plan <key> --json\`. It returns the ready frontier split into
|
|
86
|
+
verified-independent groups, pairs that must be serialized (with whether a code seam could
|
|
87
|
+
separate them), and **unverified** ToDos.
|
|
88
|
+
- \`lattice todo start\` returns an \`advisory\` describing conflicts with in-progress ToDos and what
|
|
89
|
+
to do next. \`coverage: "missing"\` means "not judged yet" — never "no conflicts".
|
|
90
|
+
- Run \`lattice todo --help\` for the declare → compile → read workflow.
|
|
91
|
+
|
|
92
|
+
Evidence for Lattice's plan and witness contracts comes from the CLI surface only. Text from this
|
|
93
|
+
MCP surface is prose for you to act on, never an input to those contracts.
|
|
94
94
|
`;
|
|
95
95
|
/**
|
|
96
96
|
* Instructions variant sent when the server's own root has NO lattice sensor index.
|
|
@@ -104,27 +104,27 @@ MCP surface is prose for you to act on, never an input to those contracts.
|
|
|
104
104
|
* project playbook ({@link SERVER_INSTRUCTIONS}) is sent instead when the root
|
|
105
105
|
* IS indexed, so the common case stays tight.
|
|
106
106
|
*/
|
|
107
|
-
exports.SERVER_INSTRUCTIONS_NO_ROOT_INDEX = `# Lattice sensor — available (per-project; pass projectPath)
|
|
108
|
-
|
|
109
|
-
Provider identity: lattice. The lattice_sensor_* names below are compatibility tool names served by Lattice's own bundled sensor; they do not call or require the independent Lattice sensor product.
|
|
110
|
-
|
|
111
|
-
Lattice sensor is a SQLite knowledge graph of a codebase's symbols, edges, and
|
|
112
|
-
files: one \`lattice_sensor_explore\` call returns the verbatim, line-numbered source
|
|
113
|
-
of the relevant symbols PLUS the call paths between them and a blast-radius
|
|
114
|
-
summary — replacing a grep + Read loop with one round-trip.
|
|
115
|
-
|
|
116
|
-
This server started somewhere with no \`.lattice/sensor/\` of its own, so there is no
|
|
117
|
-
default project — but the tools are available and work **per project**:
|
|
118
|
-
|
|
119
|
-
- To query a project that HAS a \`.lattice/sensor/\` index (e.g. a service inside a
|
|
120
|
-
monorepo, or a second repo), pass its path as \`projectPath\` to
|
|
121
|
-
\`lattice_sensor_explore\` (and any other lattice sensor tool). Lattice sensor resolves the
|
|
122
|
-
nearest \`.lattice/sensor/\` at or above that path and answers from it — for as many
|
|
123
|
-
projects as you like in one session.
|
|
124
|
-
- For a project with no \`.lattice/sensor/\`, decide whether the expected reduction in
|
|
125
|
-
repeated Read/Grep work justifies the one-time indexing cost. When workspace writes
|
|
126
|
-
and shell execution are allowed, you may run \`lattice sensor init <projectPath> --json\`
|
|
127
|
-
yourself and then retry with that \`projectPath\`; otherwise use built-in tools and
|
|
128
|
-
tell the user the exact init command. A new index is picked up live, with no restart.
|
|
107
|
+
exports.SERVER_INSTRUCTIONS_NO_ROOT_INDEX = `# Lattice sensor — available (per-project; pass projectPath)
|
|
108
|
+
|
|
109
|
+
Provider identity: lattice. The lattice_sensor_* names below are compatibility tool names served by Lattice's own bundled sensor; they do not call or require the independent Lattice sensor product.
|
|
110
|
+
|
|
111
|
+
Lattice sensor is a SQLite knowledge graph of a codebase's symbols, edges, and
|
|
112
|
+
files: one \`lattice_sensor_explore\` call returns the verbatim, line-numbered source
|
|
113
|
+
of the relevant symbols PLUS the call paths between them and a blast-radius
|
|
114
|
+
summary — replacing a grep + Read loop with one round-trip.
|
|
115
|
+
|
|
116
|
+
This server started somewhere with no \`.lattice/sensor/\` of its own, so there is no
|
|
117
|
+
default project — but the tools are available and work **per project**:
|
|
118
|
+
|
|
119
|
+
- To query a project that HAS a \`.lattice/sensor/\` index (e.g. a service inside a
|
|
120
|
+
monorepo, or a second repo), pass its path as \`projectPath\` to
|
|
121
|
+
\`lattice_sensor_explore\` (and any other lattice sensor tool). Lattice sensor resolves the
|
|
122
|
+
nearest \`.lattice/sensor/\` at or above that path and answers from it — for as many
|
|
123
|
+
projects as you like in one session.
|
|
124
|
+
- For a project with no \`.lattice/sensor/\`, decide whether the expected reduction in
|
|
125
|
+
repeated Read/Grep work justifies the one-time indexing cost. When workspace writes
|
|
126
|
+
and shell execution are allowed, you may run \`lattice sensor init <projectPath> --json\`
|
|
127
|
+
yourself and then retry with that \`projectPath\`; otherwise use built-in tools and
|
|
128
|
+
tell the user the exact init command. A new index is picked up live, with no restart.
|
|
129
129
|
`;
|
|
130
130
|
//# sourceMappingURL=server-instructions.js.map
|
|
@@ -173,7 +173,7 @@ function worktreeMismatchNotice(m) {
|
|
|
173
173
|
/** Resolve symlinks where possible so tmp/realpath quirks don't break equality. */
|
|
174
174
|
function realpath(p) {
|
|
175
175
|
try {
|
|
176
|
-
return fs.realpathSync(path.resolve(p));
|
|
176
|
+
return fs.realpathSync.native(path.resolve(p));
|
|
177
177
|
}
|
|
178
178
|
catch {
|
|
179
179
|
return path.resolve(p);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worktree.js","sourceRoot":"","sources":["../../src/sync/worktree.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"worktree.js","sourceRoot":"","sources":["../../src/sync/worktree.ts"],"names":[],"mappings":"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"}
|
package/sensor/package.json
CHANGED
|
@@ -1,56 +1,56 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@quolu/lattice-sensor",
|
|
3
|
-
"version": "0.7.3-lattice.1",
|
|
4
|
-
"private": true,
|
|
5
|
-
"description": "Lattice-owned local structural sensor.",
|
|
6
|
-
"repository": {
|
|
7
|
-
"type": "git",
|
|
8
|
-
"url": "git+https://github.com/kitepon
|
|
9
|
-
},
|
|
10
|
-
"main": "dist/index.js",
|
|
11
|
-
"types": "dist/index.d.ts",
|
|
12
|
-
"files": [
|
|
13
|
-
"dist",
|
|
14
|
-
"README.md"
|
|
15
|
-
],
|
|
16
|
-
"scripts": {
|
|
17
|
-
"build": "npm run clean && tsc && npm run copy-assets",
|
|
18
|
-
"copy-assets": "node -e \"const fs=require('fs');fs.mkdirSync('dist/db',{recursive:true});fs.copyFileSync('src/db/schema.sql','dist/db/schema.sql');fs.mkdirSync('dist/extraction/wasm',{recursive:true});fs.readdirSync('src/extraction/wasm').filter(f=>f.endsWith('.wasm')).forEach(f=>fs.copyFileSync('src/extraction/wasm/'+f,'dist/extraction/wasm/'+f))\"",
|
|
19
|
-
"dev": "tsc --watch",
|
|
20
|
-
"build:kernel": "bash scripts/build-kernel.sh",
|
|
21
|
-
"test": "vitest run --maxWorkers=4 --minWorkers=1",
|
|
22
|
-
"test:watch": "vitest",
|
|
23
|
-
"test:eval": "vitest run __tests__/evaluation/",
|
|
24
|
-
"eval": "npm run build && npx tsx __tests__/evaluation/runner.ts",
|
|
25
|
-
"clean": "node -e \"const fs=require('fs');fs.rmSync('dist',{recursive:true,force:true})\""
|
|
26
|
-
},
|
|
27
|
-
"keywords": [
|
|
28
|
-
"code-intelligence",
|
|
29
|
-
"knowledge-graph",
|
|
30
|
-
"static-analysis"
|
|
31
|
-
],
|
|
32
|
-
"author": "",
|
|
33
|
-
"license": "MIT",
|
|
34
|
-
"dependencies": {
|
|
35
|
-
"@clack/prompts": "^1.3.0",
|
|
36
|
-
"commander": "^14.0.2",
|
|
37
|
-
"fast-string-width": "^3.0.2",
|
|
38
|
-
"fast-wrap-ansi": "^0.2.0",
|
|
39
|
-
"ignore": "^7.0.5",
|
|
40
|
-
"jsonc-parser": "^3.3.1",
|
|
41
|
-
"picomatch": "^4.0.4",
|
|
42
|
-
"sisteransi": "^1.0.5",
|
|
43
|
-
"tree-sitter-wasms": "^0.1.11",
|
|
44
|
-
"web-tree-sitter": "^0.25.3"
|
|
45
|
-
},
|
|
46
|
-
"devDependencies": {
|
|
47
|
-
"@types/better-sqlite3": "^7.6.0",
|
|
48
|
-
"@types/node": "^20.19.30",
|
|
49
|
-
"@types/picomatch": "^4.0.2",
|
|
50
|
-
"typescript": "^5.0.0",
|
|
51
|
-
"vitest": "^2.1.9"
|
|
52
|
-
},
|
|
53
|
-
"engines": {
|
|
54
|
-
"node": ">=20.0.0 <25.0.0 || >=26.0.0"
|
|
55
|
-
}
|
|
56
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@quolu/lattice-sensor",
|
|
3
|
+
"version": "0.7.3-lattice.1",
|
|
4
|
+
"private": true,
|
|
5
|
+
"description": "Lattice-owned local structural sensor.",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/kitepon/Lattice.git"
|
|
9
|
+
},
|
|
10
|
+
"main": "dist/index.js",
|
|
11
|
+
"types": "dist/index.d.ts",
|
|
12
|
+
"files": [
|
|
13
|
+
"dist",
|
|
14
|
+
"README.md"
|
|
15
|
+
],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "npm run clean && tsc && npm run copy-assets",
|
|
18
|
+
"copy-assets": "node -e \"const fs=require('fs');fs.mkdirSync('dist/db',{recursive:true});fs.copyFileSync('src/db/schema.sql','dist/db/schema.sql');fs.mkdirSync('dist/extraction/wasm',{recursive:true});fs.readdirSync('src/extraction/wasm').filter(f=>f.endsWith('.wasm')).forEach(f=>fs.copyFileSync('src/extraction/wasm/'+f,'dist/extraction/wasm/'+f))\"",
|
|
19
|
+
"dev": "tsc --watch",
|
|
20
|
+
"build:kernel": "bash scripts/build-kernel.sh",
|
|
21
|
+
"test": "vitest run --maxWorkers=4 --minWorkers=1",
|
|
22
|
+
"test:watch": "vitest",
|
|
23
|
+
"test:eval": "vitest run __tests__/evaluation/",
|
|
24
|
+
"eval": "npm run build && npx tsx __tests__/evaluation/runner.ts",
|
|
25
|
+
"clean": "node -e \"const fs=require('fs');fs.rmSync('dist',{recursive:true,force:true})\""
|
|
26
|
+
},
|
|
27
|
+
"keywords": [
|
|
28
|
+
"code-intelligence",
|
|
29
|
+
"knowledge-graph",
|
|
30
|
+
"static-analysis"
|
|
31
|
+
],
|
|
32
|
+
"author": "",
|
|
33
|
+
"license": "MIT",
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"@clack/prompts": "^1.3.0",
|
|
36
|
+
"commander": "^14.0.2",
|
|
37
|
+
"fast-string-width": "^3.0.2",
|
|
38
|
+
"fast-wrap-ansi": "^0.2.0",
|
|
39
|
+
"ignore": "^7.0.5",
|
|
40
|
+
"jsonc-parser": "^3.3.1",
|
|
41
|
+
"picomatch": "^4.0.4",
|
|
42
|
+
"sisteransi": "^1.0.5",
|
|
43
|
+
"tree-sitter-wasms": "^0.1.11",
|
|
44
|
+
"web-tree-sitter": "^0.25.3"
|
|
45
|
+
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@types/better-sqlite3": "^7.6.0",
|
|
48
|
+
"@types/node": "^20.19.30",
|
|
49
|
+
"@types/picomatch": "^4.0.2",
|
|
50
|
+
"typescript": "^5.0.0",
|
|
51
|
+
"vitest": "^2.1.9"
|
|
52
|
+
},
|
|
53
|
+
"engines": {
|
|
54
|
+
"node": ">=20.0.0 <25.0.0 || >=26.0.0"
|
|
55
|
+
}
|
|
56
|
+
}
|
package/src/bridge-daemon.mjs
CHANGED
|
@@ -19,8 +19,9 @@ const STOP_RECEIPT_SCHEMA = 'lattice.bridge_stop_receipt.v1';
|
|
|
19
19
|
const ACTIVE_MARKER_SCHEMA = 'lattice.bridge_daemon_active.v1';
|
|
20
20
|
const CONTROL_MAX_BYTES = 65_536;
|
|
21
21
|
/** control fileの差し替え競合だけを吸収する再読の上限と間隔(`readStrictJson`が唯一の使用者)。 */
|
|
22
|
-
const CONTROL_READ_RETRY_LIMIT =
|
|
23
|
-
const CONTROL_READ_RETRY_DELAY_MS =
|
|
22
|
+
const CONTROL_READ_RETRY_LIMIT = 50;
|
|
23
|
+
const CONTROL_READ_RETRY_DELAY_MS = 10;
|
|
24
|
+
const sleep = (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds));
|
|
24
25
|
|
|
25
26
|
export function bridgeDaemonDescriptorPath(env = process.env) {
|
|
26
27
|
return path.join(bridgeConfigPaths(env).root, 'bridge-daemon.json');
|
|
@@ -48,7 +49,14 @@ async function atomicDescriptor(ref, value) {
|
|
|
48
49
|
const temporary = `${ref}.${process.pid}.${randomBytes(8).toString('hex')}.tmp`;
|
|
49
50
|
try {
|
|
50
51
|
await writeFile(temporary, `${JSON.stringify(value)}\n`, { encoding: 'utf8', mode: 0o600, flag: 'wx' });
|
|
51
|
-
|
|
52
|
+
for (let attempt = 0;; attempt += 1) {
|
|
53
|
+
try { await rename(temporary, ref); break; }
|
|
54
|
+
catch (error) {
|
|
55
|
+
if (process.platform !== 'win32' || !['EPERM', 'EACCES'].includes(error?.code)
|
|
56
|
+
|| attempt >= CONTROL_READ_RETRY_LIMIT - 1) throw error;
|
|
57
|
+
await sleep(CONTROL_READ_RETRY_DELAY_MS);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
52
60
|
await chmod(ref, 0o600);
|
|
53
61
|
} finally { await rm(temporary, { force: true }); }
|
|
54
62
|
}
|
|
@@ -80,7 +80,7 @@ const LANDING_COPY = Object.freeze({
|
|
|
80
80
|
}),
|
|
81
81
|
});
|
|
82
82
|
|
|
83
|
-
const GITHUB_URL = 'https://github.com/kitepon
|
|
83
|
+
const GITHUB_URL = 'https://github.com/kitepon/Lattice';
|
|
84
84
|
|
|
85
85
|
export function escapeHtml(value) {
|
|
86
86
|
return String(value).replaceAll('&', '&').replaceAll('<', '<')
|
package/src/runtime-cli.mjs
CHANGED
|
@@ -4445,6 +4445,13 @@ export async function runRuntimeCli({ argv, cwd, stdout, stderr }) {
|
|
|
4445
4445
|
&& argv[0] === 'run' && argv[1] === 'activate'
|
|
4446
4446
|
&& argv[2] === '--run' && typeof argv[3] === 'string' && argv[3].length > 0) {
|
|
4447
4447
|
action = async () => {
|
|
4448
|
+
if (process.platform === 'win32') {
|
|
4449
|
+
return typedFailure(
|
|
4450
|
+
stderr,
|
|
4451
|
+
'PLATFORM_UNSUPPORTED',
|
|
4452
|
+
'Lattice managed runtime v1 is POSIX-only; use WSL2 on Windows',
|
|
4453
|
+
);
|
|
4454
|
+
}
|
|
4448
4455
|
const { repoRoot, runDir, runRef } = await resolveRunStore(cwd, argv[3]);
|
|
4449
4456
|
await requireLegacyRunMode(runDir, 'activate');
|
|
4450
4457
|
return runActivate({ runDir, runRef, repoRoot, stdout, requestId: requestIdOverride });
|
|
@@ -54,9 +54,17 @@ function sha256Bytes(bytes) { return createHash('sha256').update(bytes).digest('
|
|
|
54
54
|
const execFileAsync = promisify(execFile);
|
|
55
55
|
|
|
56
56
|
export async function observeManagedProcessStartIdentity(pid) {
|
|
57
|
+
if (!Number.isSafeInteger(pid) || pid < 1) {
|
|
58
|
+
fail('ADAPTER_CONTROLLER_UNAVAILABLE', `process start identity観測失敗: ${pid}`);
|
|
59
|
+
}
|
|
57
60
|
let startedIdentity;
|
|
58
61
|
try {
|
|
59
|
-
const
|
|
62
|
+
const executable = process.platform === 'win32' ? 'powershell.exe' : '/bin/ps';
|
|
63
|
+
const args = process.platform === 'win32'
|
|
64
|
+
? ['-NoProfile', '-NonInteractive', '-Command',
|
|
65
|
+
`[System.Diagnostics.Process]::GetProcessById(${pid}).StartTime.ToUniversalTime().Ticks`]
|
|
66
|
+
: ['-o', 'lstart=', '-p', String(pid)];
|
|
67
|
+
const { stdout } = await execFileAsync(executable, args, { encoding: 'utf8' });
|
|
60
68
|
startedIdentity = stdout.trim();
|
|
61
69
|
} catch { fail('ADAPTER_CONTROLLER_UNAVAILABLE', `process start identity観測失敗: ${pid}`); }
|
|
62
70
|
if (!startedIdentity) fail('ADAPTER_CONTROLLER_UNAVAILABLE', `process不在: ${pid}`);
|
|
@@ -4,15 +4,15 @@ export const SQLITE_EXPERIMENTAL_WARNING_MESSAGE =
|
|
|
4
4
|
|
|
5
5
|
export function sensorNodeRuntimeFlags(nodeVersion = process.versions.node) {
|
|
6
6
|
const major = Number(nodeVersion.split('.')[0]);
|
|
7
|
-
return major === 22 ? [SQLITE_EXPERIMENTAL_WARNING_FLAG] : [];
|
|
7
|
+
return major === 22 || major === 24 ? [SQLITE_EXPERIMENTAL_WARNING_FLAG] : [];
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
|
-
* Node 22
|
|
11
|
+
* Node 22/24 print node:sqlite's ExperimentalWarning to stderr. The CLI has a
|
|
12
12
|
* JSON-only output contract, so suppress that exact warning while node:sqlite loads.
|
|
13
13
|
* Every other process warning keeps Node's original behavior.
|
|
14
14
|
*/
|
|
15
|
-
export function
|
|
15
|
+
export function installSqliteExperimentalWarningFilter({
|
|
16
16
|
nodeVersion = process.versions.node,
|
|
17
17
|
processObject = process,
|
|
18
18
|
} = {}) {
|
package/src/todo-cli.mjs
CHANGED
|
@@ -3428,6 +3428,8 @@ export async function renderTodoGanttForProject({
|
|
|
3428
3428
|
async function serveGantt({ repoRoot, port, stdout, env, scope = DEFAULT_GANTT_SCOPE }) {
|
|
3429
3429
|
const initialStore = await readTodoStoreStable({ repoRoot });
|
|
3430
3430
|
const identity = await resolveProjectIdentity({ repoRoot, projectId: initialStore.project_id, env });
|
|
3431
|
+
let stop;
|
|
3432
|
+
const stopped = new Promise((resolve) => { stop = resolve; });
|
|
3431
3433
|
const live = await startTodoGanttLiveServer({
|
|
3432
3434
|
projectId: initialStore.project_id,
|
|
3433
3435
|
displayName: identity.displayName,
|
|
@@ -3444,6 +3446,7 @@ async function serveGantt({ repoRoot, port, stdout, env, scope = DEFAULT_GANTT_S
|
|
|
3444
3446
|
readHead: async () => ganttLiveHeadDigest({
|
|
3445
3447
|
repoRoot, store: await readTodoStoreStable({ repoRoot }),
|
|
3446
3448
|
}),
|
|
3449
|
+
onShutdown: process.platform === 'win32' ? stop : null,
|
|
3447
3450
|
});
|
|
3448
3451
|
const result = { schema: 'lattice.todo_gantt_live_result.v3', project_id: live.projectId,
|
|
3449
3452
|
resource_scope: 'project', selection_scope: scope,
|
|
@@ -3452,10 +3455,8 @@ async function serveGantt({ repoRoot, port, stdout, env, scope = DEFAULT_GANTT_S
|
|
|
3452
3455
|
host: live.host, port: live.port, project_path: live.projectPath,
|
|
3453
3456
|
url: live.url, events_url: live.eventsUrl };
|
|
3454
3457
|
stdout.write(`${JSON.stringify(result)}\n`);
|
|
3455
|
-
|
|
3456
|
-
|
|
3457
|
-
process.once('SIGINT', stop); process.once('SIGTERM', stop);
|
|
3458
|
-
});
|
|
3458
|
+
process.once('SIGINT', stop); process.once('SIGTERM', stop);
|
|
3459
|
+
await stopped;
|
|
3459
3460
|
await live.close();
|
|
3460
3461
|
return null;
|
|
3461
3462
|
}
|
|
@@ -377,6 +377,17 @@ function signalIfPresent(signalProcess, pid, signal) {
|
|
|
377
377
|
}
|
|
378
378
|
}
|
|
379
379
|
|
|
380
|
+
async function requestDaemonShutdown(descriptor) {
|
|
381
|
+
try {
|
|
382
|
+
const response = await fetch(`http://127.0.0.1:${descriptor.port}/__lattice/shutdown`, {
|
|
383
|
+
method: 'POST', signal: AbortSignal.timeout(500),
|
|
384
|
+
});
|
|
385
|
+
return response.status === 202;
|
|
386
|
+
} catch {
|
|
387
|
+
return false;
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
380
391
|
async function stopAttestedLegacyDaemon(descriptor, {
|
|
381
392
|
signalProcess = process.kill, isProcessAlive = processIsAlive, timeoutMs = 3_000,
|
|
382
393
|
} = {}) {
|
|
@@ -387,7 +398,7 @@ async function stopAttestedLegacyDaemon(descriptor, {
|
|
|
387
398
|
error.code = 'DASHBOARD_LEGACY_ATTESTATION_LOST';
|
|
388
399
|
throw error;
|
|
389
400
|
}
|
|
390
|
-
signalProcess(descriptor.pid, 'SIGTERM');
|
|
401
|
+
if (!await requestDaemonShutdown(descriptor)) signalProcess(descriptor.pid, 'SIGTERM');
|
|
391
402
|
if (await awaitDaemonStopped(descriptor, { isProcessAlive, deadline: Date.now() + timeoutMs })) return;
|
|
392
403
|
const error = new Error('legacy dashboard daemon did not stop');
|
|
393
404
|
error.code = 'DASHBOARD_LEGACY_STOP_FAILED';
|
|
@@ -406,7 +417,7 @@ async function stopStrayDaemon(descriptor, {
|
|
|
406
417
|
signalProcess = process.kill, isProcessAlive = processIsAlive, timeoutMs = 3_000,
|
|
407
418
|
} = {}) {
|
|
408
419
|
if (await daemonAttestation(descriptor) === null) return false;
|
|
409
|
-
signalIfPresent(signalProcess, descriptor.pid, 'SIGTERM');
|
|
420
|
+
if (!await requestDaemonShutdown(descriptor)) signalIfPresent(signalProcess, descriptor.pid, 'SIGTERM');
|
|
410
421
|
const half = Math.ceil(timeoutMs / 2);
|
|
411
422
|
if (await awaitDaemonStopped(descriptor, { isProcessAlive, deadline: Date.now() + half })) return true;
|
|
412
423
|
signalIfPresent(signalProcess, descriptor.pid, 'SIGKILL');
|
|
@@ -450,7 +461,7 @@ async function stopSpawnedReplacement(child, descriptor, {
|
|
|
450
461
|
|| !await isProcessAlive(child.pid);
|
|
451
462
|
return exited && await daemonAttestation(descriptor) === null;
|
|
452
463
|
};
|
|
453
|
-
child.kill('SIGTERM');
|
|
464
|
+
if (!await requestDaemonShutdown(descriptor)) child.kill('SIGTERM');
|
|
454
465
|
let deadline = Date.now() + Math.ceil(timeoutMs / 2);
|
|
455
466
|
while (Date.now() < deadline) {
|
|
456
467
|
if (await stopped()) return;
|
|
@@ -467,15 +478,24 @@ async function stopSpawnedReplacement(child, descriptor, {
|
|
|
467
478
|
throw error;
|
|
468
479
|
}
|
|
469
480
|
|
|
470
|
-
|
|
481
|
+
function currentDaemonRecord(port) {
|
|
482
|
+
return { schema: DAEMON_SCHEMA, pid: process.pid, port,
|
|
483
|
+
started_at: new Date().toISOString() };
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
export async function writeTodoDashboardDaemonRecord({ port, env = process.env }) {
|
|
471
487
|
if (!Number.isSafeInteger(port) || port <= 0 || port > 65_535) throw new TypeError('daemon port invalid');
|
|
472
488
|
const refs = paths(env);
|
|
473
489
|
await mkdir(refs.daemons, { recursive: true, mode: 0o700 });
|
|
474
|
-
const record =
|
|
475
|
-
started_at: new Date().toISOString() };
|
|
476
|
-
// 記録を先に置く。descriptorだけが在って記録が無い瞬間を作ると、その隙に起動側が
|
|
477
|
-
// 死んだ時に、まさに直そうとしている「誰からも観測されないdaemon」が生まれる。
|
|
490
|
+
const record = currentDaemonRecord(port);
|
|
478
491
|
await atomicJson(daemonRecordRef(refs, process.pid), record);
|
|
492
|
+
return record;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
export async function writeTodoDashboardDaemonDescriptor({ port, env = process.env }) {
|
|
496
|
+
const refs = paths(env);
|
|
497
|
+
// 直接descriptorを公開する呼出面でも、孤児を再発見できるdaemon固有記録を先に置く。
|
|
498
|
+
const record = await writeTodoDashboardDaemonRecord({ port, env });
|
|
479
499
|
await atomicJson(refs.descriptor, record);
|
|
480
500
|
}
|
|
481
501
|
|
|
@@ -545,7 +565,8 @@ export async function ensureTodoDashboardDaemon({ env = process.env, spawnDaemon
|
|
|
545
565
|
const deadline = Date.now() + startupTimeoutMs;
|
|
546
566
|
while (Date.now() < deadline) {
|
|
547
567
|
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
548
|
-
const descriptor =
|
|
568
|
+
const descriptor = typeof child.pid === 'number'
|
|
569
|
+
? await readJson(daemonRecordRef(refs, child.pid), null) : null;
|
|
549
570
|
const healthy = await daemonHealthy(descriptor);
|
|
550
571
|
if (!healthy && typeof child.pid === 'number'
|
|
551
572
|
&& !await replacementIsProcessAlive(child.pid)) break;
|
|
@@ -557,17 +578,16 @@ export async function ensureTodoDashboardDaemon({ env = process.env, spawnDaemon
|
|
|
557
578
|
});
|
|
558
579
|
} catch (error) {
|
|
559
580
|
await stopSpawnedReplacement(child, descriptor, { isProcessAlive: replacementIsProcessAlive });
|
|
560
|
-
await atomicJson(refs.descriptor, legacy);
|
|
561
581
|
throw error;
|
|
562
582
|
}
|
|
563
583
|
}
|
|
584
|
+
await atomicJson(refs.descriptor, descriptor);
|
|
564
585
|
await reap(descriptor.pid);
|
|
565
586
|
return descriptor;
|
|
566
587
|
}
|
|
567
588
|
}
|
|
568
589
|
child.kill?.('SIGTERM');
|
|
569
|
-
if (legacy
|
|
570
|
-
else await rm(refs.descriptor, { force: true });
|
|
590
|
+
if (legacy === null) await rm(refs.descriptor, { force: true });
|
|
571
591
|
const error = new Error('dashboard daemon did not become ready');
|
|
572
592
|
error.code = 'DASHBOARD_DAEMON_UNAVAILABLE';
|
|
573
593
|
throw error;
|