af360 0.1.4 → 0.1.11
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/.next/BUILD_ID +1 -1
- package/dist/.next/app-build-manifest.json +83 -83
- package/dist/.next/app-path-routes-manifest.json +19 -19
- package/dist/.next/build-manifest.json +2 -2
- package/dist/.next/prerender-manifest.json +36 -36
- package/dist/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/dist/.next/server/app/_not-found.html +1 -1
- package/dist/.next/server/app/_not-found.rsc +3 -3
- package/dist/.next/server/app/ahead/page.js +1 -1
- package/dist/.next/server/app/ahead/page_client-reference-manifest.js +1 -1
- package/dist/.next/server/app/ahead.html +1 -1
- package/dist/.next/server/app/ahead.rsc +4 -4
- package/dist/.next/server/app/api/browse/route_client-reference-manifest.js +1 -1
- package/dist/.next/server/app/api/card/route.js +1 -1
- package/dist/.next/server/app/api/card/route.js.nft.json +1 -1
- package/dist/.next/server/app/api/card/route_client-reference-manifest.js +1 -1
- package/dist/.next/server/app/api/check/route_client-reference-manifest.js +1 -1
- package/dist/.next/server/app/api/config/route_client-reference-manifest.js +1 -1
- package/dist/.next/server/app/api/connections/route_client-reference-manifest.js +1 -1
- package/dist/.next/server/app/api/connectors/github/route_client-reference-manifest.js +1 -1
- package/dist/.next/server/app/api/consent/route_client-reference-manifest.js +1 -1
- package/dist/.next/server/app/api/context/route_client-reference-manifest.js +1 -1
- package/dist/.next/server/app/api/discover/route_client-reference-manifest.js +1 -1
- package/dist/.next/server/app/api/expiry/route_client-reference-manifest.js +1 -1
- package/dist/.next/server/app/api/first-light/route_client-reference-manifest.js +1 -1
- package/dist/.next/server/app/api/handoff/route_client-reference-manifest.js +1 -1
- package/dist/.next/server/app/api/health/route_client-reference-manifest.js +1 -1
- package/dist/.next/server/app/api/incidents/route_client-reference-manifest.js +1 -1
- package/dist/.next/server/app/api/insights/route.js +1 -1
- package/dist/.next/server/app/api/insights/route.js.nft.json +1 -1
- package/dist/.next/server/app/api/insights/route_client-reference-manifest.js +1 -1
- package/dist/.next/server/app/api/log/route.js +1 -1
- package/dist/.next/server/app/api/log/route_client-reference-manifest.js +1 -1
- package/dist/.next/server/app/api/pulse/route_client-reference-manifest.js +1 -1
- package/dist/.next/server/app/api/radar/route_client-reference-manifest.js +1 -1
- package/dist/.next/server/app/api/report/route.js +1 -1
- package/dist/.next/server/app/api/report/route.js.nft.json +1 -1
- package/dist/.next/server/app/api/report/route_client-reference-manifest.js +1 -1
- package/dist/.next/server/app/api/services/route_client-reference-manifest.js +1 -1
- package/dist/.next/server/app/api/status/route_client-reference-manifest.js +1 -1
- package/dist/.next/server/app/connections/page.js +1 -1
- package/dist/.next/server/app/connections/page_client-reference-manifest.js +1 -1
- package/dist/.next/server/app/connections.html +1 -1
- package/dist/.next/server/app/connections.rsc +4 -4
- package/dist/.next/server/app/dashboard/page_client-reference-manifest.js +1 -1
- package/dist/.next/server/app/dashboard.html +1 -1
- package/dist/.next/server/app/dashboard.rsc +3 -3
- package/dist/.next/server/app/discoveries/page.js +1 -1
- package/dist/.next/server/app/discoveries/page_client-reference-manifest.js +1 -1
- package/dist/.next/server/app/discoveries.html +1 -1
- package/dist/.next/server/app/discoveries.rsc +4 -4
- package/dist/.next/server/app/expiry/page_client-reference-manifest.js +1 -1
- package/dist/.next/server/app/expiry.html +1 -1
- package/dist/.next/server/app/expiry.rsc +3 -3
- package/dist/.next/server/app/fleet/page_client-reference-manifest.js +1 -1
- package/dist/.next/server/app/fleet.html +1 -1
- package/dist/.next/server/app/fleet.rsc +3 -3
- package/dist/.next/server/app/home/page_client-reference-manifest.js +1 -1
- package/dist/.next/server/app/home.html +1 -1
- package/dist/.next/server/app/home.rsc +3 -3
- package/dist/.next/server/app/legal/privacy/page_client-reference-manifest.js +1 -1
- package/dist/.next/server/app/legal/terms/page_client-reference-manifest.js +1 -1
- package/dist/.next/server/app/log/page_client-reference-manifest.js +1 -1
- package/dist/.next/server/app/log.html +1 -1
- package/dist/.next/server/app/log.rsc +4 -4
- package/dist/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dist/.next/server/app/projects/page_client-reference-manifest.js +1 -1
- package/dist/.next/server/app/projects.html +1 -1
- package/dist/.next/server/app/projects.rsc +4 -4
- package/dist/.next/server/app/radar/page.js +1 -1
- package/dist/.next/server/app/radar/page_client-reference-manifest.js +1 -1
- package/dist/.next/server/app/radar.html +1 -1
- package/dist/.next/server/app/radar.rsc +4 -4
- package/dist/.next/server/app/report/page.js +1 -1
- package/dist/.next/server/app/report/page_client-reference-manifest.js +1 -1
- package/dist/.next/server/app/report.html +1 -1
- package/dist/.next/server/app/report.rsc +4 -4
- package/dist/.next/server/app/settings/page.js +1 -1
- package/dist/.next/server/app/settings/page_client-reference-manifest.js +1 -1
- package/dist/.next/server/app/settings.html +1 -1
- package/dist/.next/server/app/settings.rsc +4 -4
- package/dist/.next/server/app/sites/page_client-reference-manifest.js +1 -1
- package/dist/.next/server/app/sites.html +1 -1
- package/dist/.next/server/app/sites.rsc +4 -4
- package/dist/.next/server/app/welcome/page_client-reference-manifest.js +1 -1
- package/dist/.next/server/app/welcome.html +1 -1
- package/dist/.next/server/app/welcome.rsc +4 -4
- package/dist/.next/server/app-paths-manifest.json +19 -19
- package/dist/.next/server/chunks/1155.js +1 -0
- package/dist/.next/server/chunks/2346.js +1 -1
- package/dist/.next/server/chunks/2465.js +1 -1
- package/dist/.next/server/chunks/9170.js +1 -1
- package/dist/.next/server/middleware-manifest.json +1 -1
- package/dist/.next/server/pages/404.html +1 -1
- package/dist/.next/server/pages/500.html +1 -1
- package/dist/.next/server/pages-manifest.json +1 -1
- package/dist/.next/static/chunks/3192-f33976256a7713fd.js +1 -0
- package/dist/.next/static/chunks/{5449-42f9c47cf519229a.js → 5449-1f71ab05b6de2699.js} +1 -1
- package/dist/.next/static/chunks/app/ahead/page-ec9c355d92be3655.js +1 -0
- package/dist/.next/static/chunks/app/connections/page-78928db455ee443e.js +1 -0
- package/dist/.next/static/chunks/app/discoveries/page-09ae376238d3c1da.js +1 -0
- package/dist/.next/static/chunks/app/radar/page-ca0fa3338fe9ddb4.js +1 -0
- package/dist/.next/static/chunks/app/report/page-b6eef7480ac39e24.js +1 -0
- package/dist/.next/static/chunks/app/settings/{page-3ca6b23c69637aab.js → page-dd56fc2e097505c7.js} +1 -1
- package/dist/.next/static/css/9db3c04b1822381e.css +1 -0
- package/dist/build-id.json +114 -114
- package/dist/package.json +8 -9
- package/dist/shell/bin/af360-bridge.exe +0 -0
- package/lib/mcpActivity.mjs +318 -23
- package/package.json +8 -9
- package/shell/bin/af360-bridge.exe +0 -0
- package/dist/.next/server/chunks/9601.js +0 -1
- package/dist/.next/static/chunks/3192-3df9f9fedb9e38b1.js +0 -1
- package/dist/.next/static/chunks/app/ahead/page-2d37c636630d12e7.js +0 -1
- package/dist/.next/static/chunks/app/connections/page-7e0dbe13ce939fc9.js +0 -1
- package/dist/.next/static/chunks/app/discoveries/page-0ac8bd1bf0178837.js +0 -1
- package/dist/.next/static/chunks/app/radar/page-24540a7c154a41b8.js +0 -1
- package/dist/.next/static/chunks/app/report/page-f1ede34a209ac047.js +0 -1
- package/dist/.next/static/css/f0c4f79b3d7295b1.css +0 -1
- /package/dist/.next/static/{235399e935b20d0efd52d → 24e7279870f90176b29aa}/_buildManifest.js +0 -0
- /package/dist/.next/static/{235399e935b20d0efd52d → 24e7279870f90176b29aa}/_ssgManifest.js +0 -0
package/dist/package.json
CHANGED
|
@@ -1,23 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "af360",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.11",
|
|
4
4
|
"description": "Watches the things you have built - folders, repos and sites - and tells you what needs you. Runs entirely on your own machine.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"author": "Afeleos LLC",
|
|
7
7
|
"homepage": "https://afeleos.com",
|
|
8
|
-
"
|
|
9
|
-
"type": "git",
|
|
10
|
-
"url": "git+https://github.com/Afeleos-LLC/AF360.git"
|
|
11
|
-
},
|
|
12
|
-
"bugs": {
|
|
13
|
-
"url": "https://github.com/Afeleos-LLC/AF360/issues"
|
|
14
|
-
},
|
|
8
|
+
"mcpName": "com.afeleos/af360",
|
|
15
9
|
"keywords": [
|
|
16
10
|
"local-first",
|
|
17
11
|
"projects",
|
|
18
12
|
"git",
|
|
19
13
|
"monitoring",
|
|
20
|
-
"privacy"
|
|
14
|
+
"privacy",
|
|
15
|
+
"mcp",
|
|
16
|
+
"model-context-protocol"
|
|
17
|
+
],
|
|
18
|
+
"os": [
|
|
19
|
+
"win32"
|
|
21
20
|
],
|
|
22
21
|
"bin": {
|
|
23
22
|
"af360": "bin/af360.mjs"
|
|
Binary file
|
package/lib/mcpActivity.mjs
CHANGED
|
@@ -104,6 +104,67 @@
|
|
|
104
104
|
* the rail says af360 could not identify what asked, rather than guessing.
|
|
105
105
|
*
|
|
106
106
|
* ============================================================
|
|
107
|
+
* **AND ON EVERY INSTALLED COPY THE PARENT IS AF360 ITSELF** (R340, owner
|
|
108
|
+
* ruling 2026-09-05, measured on 0.1.6).
|
|
109
|
+
* ============================================================
|
|
110
|
+
*
|
|
111
|
+
* THE PARAGRAPH ABOVE IS TRUE AND WAS NOT ENOUGH, AND THE SENTENCE THAT GAVE
|
|
112
|
+
* IT AWAY IS FOUR LINES UP: *"the process that spawned this one, which for an
|
|
113
|
+
* MCP server is the client itself."* **THAT STOPPED BEING TRUE WHEN R306
|
|
114
|
+
* SHIPPED.** A packaged install writes the alias entry `af360.exe mcp`; the
|
|
115
|
+
* alias resolves to af360's own native host; and that host starts node on
|
|
116
|
+
* bin/af360.mjs AS A CHILD. The client is this process's GRANDparent.
|
|
117
|
+
*
|
|
118
|
+
* So the owner read `estate_status asked by af360` three times over a Log room
|
|
119
|
+
* whose whole purpose is naming who asked, and af360 was naming itself - the
|
|
120
|
+
* exact defect guard 4 exists to prevent, arriving through the one name the
|
|
121
|
+
* guard did not know was its own.
|
|
122
|
+
*
|
|
123
|
+
* **THE HONEST ANSWER SHIPS AND THE REAL ONE IS OWED.** `observeCaller` now
|
|
124
|
+
* refuses OWN_APP as flatly as it refuses the runtime, so the record says af360
|
|
125
|
+
* could not identify what asked - which is TRUE, and which a reader can act on.
|
|
126
|
+
* Naming the client for real means walking up one more hop, `caller-name`
|
|
127
|
+
* answers with a name rather than a pid, and a parent-of-pid verb is a NEW DOOR
|
|
128
|
+
* in af360-bridge.exe. **THAT IS THE OWNER'S TO RULE (RULINGS 001) AND IT IS
|
|
129
|
+
* RECORDED AS OWED IN 0b.4, NOT TAKEN QUIETLY HERE.**
|
|
130
|
+
*
|
|
131
|
+
* ============================================================
|
|
132
|
+
* **AND HE RULED IT. THE DEBT ABOVE IS PAID** (R349/R350, owner ruling
|
|
133
|
+
* 2026-09-05, measured on the installed 0.1.7 before a line was written).
|
|
134
|
+
* ============================================================
|
|
135
|
+
*
|
|
136
|
+
* **THE PARAGRAPH ABOVE IS KEPT WHOLE AND NOT REWRITTEN** (RULINGS 65): a debt
|
|
137
|
+
* that was named, carried for a day and then paid is a different fact from one
|
|
138
|
+
* nobody ever wrote down, and only one of those is true here.
|
|
139
|
+
*
|
|
140
|
+
* `caller-chain` is the door, the owner opened it, and `callerFromChain` is the
|
|
141
|
+
* rule that reads it - **which is NOT the rule R350 was drafted with.** Driven
|
|
142
|
+
* against this machine's live client before it was built, the drafted rule
|
|
143
|
+
* answered `cmd`, because the client spawns af360 through a shell. Driven
|
|
144
|
+
* against a node-based client it answered `powershell`, the client's own
|
|
145
|
+
* launcher. Two false sentences, both found by measuring rather than by
|
|
146
|
+
* reasoning, which is R349's whole reason for ordering the measurement first.
|
|
147
|
+
*
|
|
148
|
+
* **WHAT DID NOT CHANGE, AND IT IS EVERY GUARD THIS FILE CLAIMS.** The four
|
|
149
|
+
* guards below hold exactly as written: `observeCaller` still takes no
|
|
150
|
+
* parameters, the binary is still found without the environment, the mask still
|
|
151
|
+
* runs - now on EVERY hop rather than on one - and the shape gate still has a
|
|
152
|
+
* constant fallback. **AND ONE CLAIM GOT STRONGER RATHER THAN WEAKER**: the old
|
|
153
|
+
* verb opened a process HANDLE to read a name; the new one reads a snapshot
|
|
154
|
+
* struct and opens no handle on any walked process at all, so "af360 cannot
|
|
155
|
+
* start, stop or signal anything through this door" became a property of the
|
|
156
|
+
* code instead of a promise about it.
|
|
157
|
+
*
|
|
158
|
+
* THE OTHER HALF OF WHAT WAS MEASURED, BECAUSE A HALF-ANSWERED QUESTION READS
|
|
159
|
+
* AS A WHOLE ONE: every `tools/call` IS logged - `noteToolCall` sits before the
|
|
160
|
+
* branch in scripts/mcp-server.mjs and cannot be skipped by an unknown tool, a
|
|
161
|
+
* refusal or a config fault - and REPEATS COLLAPSE FOR DISPLAY ONLY, per tool
|
|
162
|
+
* and per caller, inside `COLLAPSE_MS`, rendered `x3` (lib/mcpRail.mjs
|
|
163
|
+
* `collapse`). Nothing is dropped from the file. **AN ASK THAT NEVER REACHED
|
|
164
|
+
* THIS SERVER LEAVES NO TRACE HERE AND CANNOT**: a client that answers from its
|
|
165
|
+
* own context did not ask af360, and af360 must not invent a line for it.
|
|
166
|
+
*
|
|
167
|
+
* ============================================================
|
|
107
168
|
* ONE FILE, IN AF360'S OWN HOME, APPEND-ONLY, CAPPED (RULINGS 56a, 56c)
|
|
108
169
|
* ============================================================
|
|
109
170
|
*
|
|
@@ -203,6 +264,58 @@ export const UNIDENTIFIED = "unidentified";
|
|
|
203
264
|
*/
|
|
204
265
|
export const CALLER_SHAPE = /^[a-z0-9][a-z0-9._+-]{0,31}$/;
|
|
205
266
|
|
|
267
|
+
/**
|
|
268
|
+
* AF360'S OWN IMAGE NAME, AS WINDOWS REPORTS IT (R340, owner ruling
|
|
269
|
+
* 2026-09-05).
|
|
270
|
+
*
|
|
271
|
+
* THE BRIDGE RETURNS `ProcessName`, WHICH CARRIES NO EXTENSION - "af360", not
|
|
272
|
+
* "af360.exe" - so this is the alias name with its `.exe` already off. It is
|
|
273
|
+
* the one literal in this file that has a twin elsewhere (`ALIAS_NAME` in
|
|
274
|
+
* lib/connections.mjs) and it is NOT imported from there: that module reaches
|
|
275
|
+
* a config parser and a filesystem walk, and this one is loaded by the cockpit
|
|
276
|
+
* for its path constants. A four-character duplicate is cheaper than that
|
|
277
|
+
* graph, and scripts/mcp-fixture.mjs asserts the two agree so the duplicate
|
|
278
|
+
* cannot drift.
|
|
279
|
+
*
|
|
280
|
+
* IT IS COMPARED, NEVER WRITTEN. Like every other value here it can only ever
|
|
281
|
+
* cause UNIDENTIFIED to be recorded; no branch puts it in a line.
|
|
282
|
+
*/
|
|
283
|
+
export const OWN_APP = "af360";
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* THE SHELLS af360 WALKS STRAIGHT PAST (R349/R350, owner ruling 2026-09-05).
|
|
287
|
+
*
|
|
288
|
+
* **THE MEASUREMENT THAT PUT THIS LIST HERE, AND IT WAS TAKEN OFF THE OWNER'S
|
|
289
|
+
* OWN LIVE CLIENT.** R350 as drafted said the asker is *"the first ancestor
|
|
290
|
+
* that is neither af360's own runtime nor its executable"*. Run against the
|
|
291
|
+
* real chain on 2026-09-05, that rule answered `cmd`:
|
|
292
|
+
*
|
|
293
|
+
* node -> af360 -> cmd -> claude -> sh
|
|
294
|
+
* ^^^ the rule as drafted stopped here
|
|
295
|
+
*
|
|
296
|
+
* `.claude.json` registers af360 as `"command": "af360.exe"`, and the client
|
|
297
|
+
* spawns that through `cmd /d /s /c "af360.exe ^"mcp^""`. **SO THERE IS A
|
|
298
|
+
* SHELL BETWEEN AF360'S HOST AND THE CLIENT, AND `estate_status asked by cmd`
|
|
299
|
+
* IS R340'S DEFECT WEARING A DIFFERENT NAME** - a false sentence, which is the
|
|
300
|
+
* worst thing this repo can ship (CLAUDE.md 0).
|
|
301
|
+
*
|
|
302
|
+
* **THE OWNER RULED THE LIST RATHER THAN A SESSION GUESSING IT** (2026-09-05,
|
|
303
|
+
* on the measurement above): *"shells are plumbing, not askers."* A shell does
|
|
304
|
+
* not ask af360 anything; it is only ever interposed by the client's own spawn,
|
|
305
|
+
* so walking past one lands on the client rather than away from it.
|
|
306
|
+
*
|
|
307
|
+
* **IT IS A SKIP LIST AND `node` IS NOT ON IT, AND THAT DISTINCTION IS THE
|
|
308
|
+
* WHOLE RULING.** See `callerFromChain`: a conduit is walked THROUGH, a runtime
|
|
309
|
+
* is walked INTO A STOP. Adding `node` here would name a node client's
|
|
310
|
+
* launcher, which is the second false sentence the measurement found.
|
|
311
|
+
*/
|
|
312
|
+
export const CONDUIT = Object.freeze(["cmd", "powershell", "pwsh", "sh", "bash"]);
|
|
313
|
+
|
|
314
|
+
/** THE WALK'S CEILING ON THIS SIDE, and it is the bridge's own `ChainMax`.
|
|
315
|
+
* A second bound in a second language is a bound that drifts, so
|
|
316
|
+
* scripts/bridge-doors-fixture.mjs asserts the two numbers agree. */
|
|
317
|
+
export const CHAIN_MAX = 16;
|
|
318
|
+
|
|
206
319
|
/** THE OBSERVED NAME, and it starts as the honest answer rather than as null:
|
|
207
320
|
* until af360 has looked, af360 has not identified anything. */
|
|
208
321
|
let CALLER = UNIDENTIFIED;
|
|
@@ -223,17 +336,34 @@ export function callerName() {
|
|
|
223
336
|
*
|
|
224
337
|
* EVERY FAILURE IS THE SAME FAILURE: the constant. No bridge (an npm install,
|
|
225
338
|
* a Mac, a tree nobody has built the shell in), a dead parent, a name the shape
|
|
226
|
-
* gate refuses, af360's own runtime looking back
|
|
227
|
-
* UNIDENTIFIED, and the rail then says
|
|
339
|
+
* gate refuses, af360's own runtime looking back, AF360'S OWN APP LOOKING BACK
|
|
340
|
+
* (R340) - all of them leave CALLER at UNIDENTIFIED, and the rail then says
|
|
341
|
+
* af360 could not identify what asked.
|
|
228
342
|
* NOTHING HERE MAY EVER FAIL AN ANSWER, so it cannot throw.
|
|
343
|
+
*
|
|
344
|
+
* **WHAT IT DOES SINCE R340 IS READ THE KERNEL AND ASK ~~`callerFrom`~~
|
|
345
|
+
* `callerFromChain` (R349/R350).** Every rule that decides moved there so a
|
|
346
|
+
* fixture can drive it with a name this machine's process tree does not happen
|
|
347
|
+
* to contain; this function keeps the two things only it can do - the ppid and
|
|
348
|
+
* the bridge - and keeps guard 1.
|
|
349
|
+
*
|
|
350
|
+
* **AND THE VERB IT ASKS CHANGED ON 2026-09-05, WHICH IS THE DEBT R340 WROTE
|
|
351
|
+
* DOWN BEING PAID.** `caller-name` answered ONE hop, and on every packaged
|
|
352
|
+
* install that hop is af360's own host, so af360 could only ever say it could
|
|
353
|
+
* not tell. `caller-chain` answers the ancestors by name, af360 walks them, and
|
|
354
|
+
* the client is named where the walk can name it.
|
|
229
355
|
*/
|
|
230
356
|
export async function observeCaller() {
|
|
231
357
|
if (looked) return CALLER;
|
|
232
358
|
looked = true;
|
|
233
359
|
try {
|
|
234
360
|
/* THE KERNEL'S OWN NUMBER. Node did not choose it and a caller cannot set
|
|
235
|
-
it: it is the process that spawned this one
|
|
236
|
-
the client itself
|
|
361
|
+
it: it is the process that spawned this one.
|
|
362
|
+
~~"which for an MCP server is the client itself"~~ **AND THAT CLAUSE WAS
|
|
363
|
+
THE DEFECT** (R340). It is the client on a `node <entry> mcp` entry and
|
|
364
|
+
it is AF360'S OWN HOST on the alias entry every packaged install writes.
|
|
365
|
+
The number is still unforgeable; what it points AT depends on how af360
|
|
366
|
+
was started, and this file may not assume one shape. */
|
|
237
367
|
const ppid = process.ppid;
|
|
238
368
|
if (!Number.isInteger(ppid) || ppid <= 0) return CALLER;
|
|
239
369
|
|
|
@@ -244,31 +374,196 @@ export async function observeCaller() {
|
|
|
244
374
|
|
|
245
375
|
/* `fixedPath` refuses AF360_BRIDGE - guard 2 in the header, and the whole
|
|
246
376
|
reason lib/bridge.mjs grew a second resolver. Two seconds is generous
|
|
247
|
-
against a measured 149ms round trip
|
|
248
|
-
|
|
377
|
+
against a measured 149ms round trip - the chain walk was measured at
|
|
378
|
+
~77ms on 2026-09-05, snapshot included - and it runs once. */
|
|
379
|
+
/* **IT IS THE ppid AND NOT `process.pid`, AND THAT IS LOAD-BEARING RATHER
|
|
380
|
+
THAN INCIDENTAL.** The chain comes back nearest-first, so sending this
|
|
381
|
+
process's own id would put af360's OWN node at the head of it - and
|
|
382
|
+
`callerFromChain` STOPS at a runtime, so every answer on every machine
|
|
383
|
+
would silently become the constant. This exact confusion produced a wrong
|
|
384
|
+
answer while this was being driven on 2026-09-05, against real data, and
|
|
385
|
+
it is written here because the failure is INVISIBLE: nothing throws,
|
|
386
|
+
nothing logs, af360 just quietly stops naming anybody.
|
|
387
|
+
scripts/mcp-rail-fixture.mjs asserts the call site passes `ppid`. */
|
|
388
|
+
const r = await bridge("caller-chain", String(ppid), { fixedPath: true, timeout: 2_000 });
|
|
249
389
|
if (!r.ok) return CALLER;
|
|
250
390
|
|
|
251
|
-
|
|
252
|
-
name the mask ate comes back as "[secret masked]", which has brackets and
|
|
253
|
-
a space in it, so the gate refuses it and af360 says it could not
|
|
254
|
-
identify the caller - rather than writing af360's own redaction marker
|
|
255
|
-
into a row as though it were somebody's name. */
|
|
256
|
-
const seen = mask(String(r.out ?? "")).trim().toLowerCase();
|
|
257
|
-
|
|
258
|
-
/* AF360'S OWN RUNTIME IS NOT AN ANSWER (RULINGS 42a). A wrapper script
|
|
259
|
-
between the client and af360 leaves this process's parent as node, and
|
|
260
|
-
"node asked" would be af360 naming itself as the agent. The comparison is
|
|
261
|
-
against THIS process's own executable rather than the literal alone, so a
|
|
262
|
-
renamed runtime is caught too. */
|
|
263
|
-
const ownRuntime = path.basename(process.execPath, ".exe").toLowerCase();
|
|
264
|
-
if (seen === "node" || seen === ownRuntime) return CALLER;
|
|
265
|
-
|
|
266
|
-
if (!CALLER_SHAPE.test(seen)) return CALLER;
|
|
267
|
-
CALLER = seen;
|
|
391
|
+
CALLER = callerFromChain(r.out);
|
|
268
392
|
} catch { /* a courtesy to the rail must never become a failed answer */ }
|
|
269
393
|
return CALLER;
|
|
270
394
|
}
|
|
271
395
|
|
|
396
|
+
/**
|
|
397
|
+
* THE WHOLE DECISION, AND NOTHING BUT THE DECISION (R340, 2026-09-05).
|
|
398
|
+
*
|
|
399
|
+
* ============================================================
|
|
400
|
+
* WHY IT IS A FUNCTION, AND WHY IT TAKES THE ARGUMENT observeCaller REFUSES
|
|
401
|
+
* ============================================================
|
|
402
|
+
*
|
|
403
|
+
* R340's fixture has to DRIVE TWO DISTINCT CLIENTS and watch each get named.
|
|
404
|
+
* `observeCaller` reads the kernel, so on this machine it can only ever
|
|
405
|
+
* observe one parent, and a fixture that asserts anything about a second would
|
|
406
|
+
* have to REBUILD these rules beside them. **A TWIN OF A REDACTION-SHAPED RULE
|
|
407
|
+
* IS A RULE THAT DRIFTS**, and this repo has already ruled that twice (RULINGS
|
|
408
|
+
* 44a; lib/shareExport.mjs's own header). So the rules move to where a fixture
|
|
409
|
+
* can reach the SHIPPING copy, and `observeCaller` is what remains: a kernel
|
|
410
|
+
* read, and a call to this.
|
|
411
|
+
*
|
|
412
|
+
* **THE NO-PARAMETER GUARD IS NOT WEAKENED, BECAUSE THE GUARD WAS NEVER ABOUT
|
|
413
|
+
* THIS FUNCTION.** Guard 1 says nothing UPSTREAM can hand this module a name -
|
|
414
|
+
* and nothing can: `observeCaller` still takes no arguments, it is still the
|
|
415
|
+
* only caller of this in the shipping path, and it still feeds it one value it
|
|
416
|
+
* got from the bridge. This function RETURNS and never assigns: `CALLER` has
|
|
417
|
+
* exactly one writer, four lines above, and grep proves it. A fixture calling
|
|
418
|
+
* this gets a verdict back and changes nothing about what the writer stamps.
|
|
419
|
+
*
|
|
420
|
+
* EVERY REFUSAL RETURNS THE SAME CONSTANT, and there are five:
|
|
421
|
+
*
|
|
422
|
+
* 1. THE MASK ATE IT (RULINGS 57b, guard 3). Run FIRST, on purpose: a name
|
|
423
|
+
* the mask redacted comes back as "[secret masked]" - brackets and a
|
|
424
|
+
* space - so the shape gate refuses it and af360 says it could not tell,
|
|
425
|
+
* rather than writing its own redaction marker as somebody's name.
|
|
426
|
+
* 2. "node" - a bare runtime is not an answer to "who asked".
|
|
427
|
+
* 3. THIS PROCESS'S OWN EXECUTABLE, compared rather than assumed, so a
|
|
428
|
+
* renamed runtime is caught too.
|
|
429
|
+
* 4. AF360'S OWN APP (R340). See OWN_APP.
|
|
430
|
+
* 5. THE SHAPE GATE. Not a filter - one narrow shape or nothing.
|
|
431
|
+
*
|
|
432
|
+
* @param {unknown} raw whatever `caller-name` printed. Compared and classified;
|
|
433
|
+
* it reaches a log line only by being RETURNED and only if it survives all
|
|
434
|
+
* five.
|
|
435
|
+
* @returns {string} the observed name, or UNIDENTIFIED.
|
|
436
|
+
*/
|
|
437
|
+
export function callerFrom(raw) {
|
|
438
|
+
const seen = mask(String(raw ?? "")).trim().toLowerCase();
|
|
439
|
+
|
|
440
|
+
/* AF360'S OWN RUNTIME IS NOT AN ANSWER (RULINGS 42a). A wrapper script
|
|
441
|
+
between the client and af360 leaves this process's parent as node, and
|
|
442
|
+
"node asked" would be af360 naming itself as the agent. The comparison is
|
|
443
|
+
against THIS process's own executable rather than the literal alone, so a
|
|
444
|
+
renamed runtime is caught too. */
|
|
445
|
+
const ownRuntime = path.basename(process.execPath, ".exe").toLowerCase();
|
|
446
|
+
if (seen === "node" || seen === ownRuntime) return UNIDENTIFIED;
|
|
447
|
+
|
|
448
|
+
/* AND NEITHER IS AF360'S OWN APP (R340, owner ruling 2026-09-05, measured
|
|
449
|
+
on the installed 0.1.6). THE LINE ABOVE HELD A RULE THIS ONE COMPLETES:
|
|
450
|
+
af360 never names itself, and for eight days it only knew how to spot
|
|
451
|
+
itself wearing the RUNTIME's name.
|
|
452
|
+
WHAT THE OWNER READ, AND IT WAS af360 ANSWERING WITH ITS OWN NAME:
|
|
453
|
+
estate_status asked by af360 - answered from af360's last look.
|
|
454
|
+
Claude Code asked. Every time.
|
|
455
|
+
THE CAUSE IS R306'S OWN REPAIR, AND IT IS NOT A REGRESSION IN IT. The
|
|
456
|
+
alias entry a packaged install writes is `af360.exe mcp`, the alias
|
|
457
|
+
resolves to `shell/bin/af360.exe`, and that executable STARTS NODE ON
|
|
458
|
+
bin/af360.mjs AS A CHILD (shell/Af360Shell.cs, McpVerb.Run). So the
|
|
459
|
+
parent of this process is not the client at all - IT IS AF360. The
|
|
460
|
+
kernel's number is still the kernel's number; what moved is what sits
|
|
461
|
+
on the other end of it.
|
|
462
|
+
BOTH SYMPTOMS ARE ONE CAUSE. Before the alias the entry was `node
|
|
463
|
+
<entry> mcp`, the parent WAS the client, and the client was Claude Code -
|
|
464
|
+
which is itself node, so the line above refused it and the row read
|
|
465
|
+
"af360 could not identify what asked". That is the single older entry in
|
|
466
|
+
the owner's log, and it was the guard working correctly.
|
|
467
|
+
**THIS IS A WRONG ANSWER BECOMING A TRUE ONE, NOT A MISSING ONE BEING
|
|
468
|
+
FILLED IN** (RULINGS 59). Naming the real client means walking UP past
|
|
469
|
+
af360's own host to its parent, and `caller-name` returns a name and not a
|
|
470
|
+
pid - so it needs a NEW BRIDGE VERB, which is a door, which is the owner's
|
|
471
|
+
(RULINGS 001) and is OWED IN 0b.4 rather than taken here. Until that ruling
|
|
472
|
+
af360 says the thing it can prove: it could not tell.
|
|
473
|
+
**THE OWNER RULED THE DOOR ON 2026-09-05 AND THE DEBT IS PAID (R349).**
|
|
474
|
+
`caller-chain` walks the ancestors and `callerFromChain` below decides over
|
|
475
|
+
them. THIS LINE DOES NOT MOVE AND MUST NOT: reaching this function with
|
|
476
|
+
`af360` still means af360 is looking at itself, and the answer to that is
|
|
477
|
+
still the honest sentence. What changed is that the CHAIN no longer STOPS
|
|
478
|
+
at af360 - it walks past it and asks this question of the next name up. */
|
|
479
|
+
if (seen === OWN_APP) return UNIDENTIFIED;
|
|
480
|
+
|
|
481
|
+
if (!CALLER_SHAPE.test(seen)) return UNIDENTIFIED;
|
|
482
|
+
return seen;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
/**
|
|
486
|
+
* THE ASKER, PICKED OUT OF THE ANCESTORS (R349/R350, owner ruling 2026-09-05).
|
|
487
|
+
*
|
|
488
|
+
* ============================================================
|
|
489
|
+
* TWO LISTS, AND THEY DO OPPOSITE THINGS. THAT IS THE RULING.
|
|
490
|
+
* ============================================================
|
|
491
|
+
*
|
|
492
|
+
* A reader who takes this for one list with two spellings has the rule
|
|
493
|
+
* backwards, so it is said plainly:
|
|
494
|
+
*
|
|
495
|
+
* A CONDUIT IS WALKED THROUGH. af360's own executable, and a shell. Neither
|
|
496
|
+
* ever ASKS af360 anything - af360 wrote the
|
|
497
|
+
* first one, and the second was interposed by
|
|
498
|
+
* the client's own spawn - so the client is
|
|
499
|
+
* further up and walking past reaches it.
|
|
500
|
+
* A RUNTIME IS WALKED INTO A `node`, and this process's own executable.
|
|
501
|
+
* STOP. af360 cannot tell a node CLIENT from a node
|
|
502
|
+
* WRAPPER around one, and the two want
|
|
503
|
+
* opposite answers. So it stops and says it
|
|
504
|
+
* could not tell.
|
|
505
|
+
*
|
|
506
|
+
* **BOTH HALVES WERE MEASURED BEFORE EITHER WAS BUILT (R349's own order), AND
|
|
507
|
+
* EACH ONE CAUGHT A FALSE SENTENCE:**
|
|
508
|
+
*
|
|
509
|
+
* the owner's live client node -> af360 -> cmd -> claude -> sh
|
|
510
|
+
* skip only af360 names `cmd` <- the client's SHELL
|
|
511
|
+
* this rule names `claude` <- the client
|
|
512
|
+
*
|
|
513
|
+
* a node-based client node -> af360 -> node -> powershell -> claude
|
|
514
|
+
* treat node as a conduit names `powershell` <- the CLIENT'S LAUNCHER
|
|
515
|
+
* this rule stops at node, says af360 could not tell
|
|
516
|
+
*
|
|
517
|
+
* **THE SECOND ROW IS WHY THE STOP EXISTS AND WHY IT IS NOT A DEFECT.** A
|
|
518
|
+
* Node-based CLI client is UNNAMEABLE BY THIS WALK, deliberately and for ever:
|
|
519
|
+
* the only thing that would separate it from a wrapper is its COMMAND LINE, and
|
|
520
|
+
* this door returns names and refuses command lines by construction
|
|
521
|
+
* (shell/Af360Bridge.cs). A limit that could only be closed by widening a
|
|
522
|
+
* security bound is a limit af360 keeps. docs/SECURITY-MODEL.md records it as
|
|
523
|
+
* one (RULINGS 63: an unproven residual is a prediction, not a disclaimer).
|
|
524
|
+
*
|
|
525
|
+
* **AND THE ANSWER AT A STOP IS THE CONSTANT, NEVER THE RUNTIME'S NAME** (the
|
|
526
|
+
* owner's own words on ruling this: *"the honest sentence, never a runtime's
|
|
527
|
+
* name in the asker slot"*). `node` never reaches the caller field. That is
|
|
528
|
+
* `callerFrom`'s existing first refusal and this function reuses it rather than
|
|
529
|
+
* restating it - a twin of a redaction-shaped rule is a rule that drifts
|
|
530
|
+
* (RULINGS 44a), which is the same argument that lifted `callerFrom` out of
|
|
531
|
+
* `observeCaller` in the first place.
|
|
532
|
+
*
|
|
533
|
+
* **THE MASK RUNS ON EVERY HOP AND NOT ONLY ON THE ONE THAT WINS** (RULINGS
|
|
534
|
+
* 57b, guard 3). A redacted name comes back as `[secret masked]`, which is not
|
|
535
|
+
* a conduit and not a runtime, so it falls to the shape gate and refuses.
|
|
536
|
+
*
|
|
537
|
+
* @param {unknown} raw whatever `caller-chain` printed: names, one per line,
|
|
538
|
+
* nearest ancestor first. Only ever COMPARED against constants in this
|
|
539
|
+
* module, exactly as the tool enum is; a value reaches a log line by being
|
|
540
|
+
* RETURNED and only after surviving `callerFrom`.
|
|
541
|
+
* @returns {string} the asker's name, or UNIDENTIFIED.
|
|
542
|
+
*/
|
|
543
|
+
export function callerFromChain(raw) {
|
|
544
|
+
let hops = 0;
|
|
545
|
+
for (const line of String(raw ?? "").split("\n")) {
|
|
546
|
+
const seen = mask(line).trim().toLowerCase();
|
|
547
|
+
if (seen === "") continue;
|
|
548
|
+
|
|
549
|
+
/* THE BRIDGE ALREADY CAPS THE WALK AT `ChainMax`. THIS SIDE CAPS IT AGAIN
|
|
550
|
+
ANYWAY, and not out of tidiness: `r.out` is a string this module did not
|
|
551
|
+
produce, and a reader of this loop should not have to go and read a C#
|
|
552
|
+
file to know it terminates. */
|
|
553
|
+
if (++hops > CHAIN_MAX) break;
|
|
554
|
+
|
|
555
|
+
if (seen === OWN_APP || CONDUIT.includes(seen)) continue;
|
|
556
|
+
|
|
557
|
+
/* THE FIRST NAME THAT IS NOT PLUMBING IS THE ANSWER, WHATEVER IT IS - and
|
|
558
|
+
`callerFrom` is what decides whether it is an answer af360 may say. A
|
|
559
|
+
runtime, a masked string and a name the shape gate refuses all come back
|
|
560
|
+
as the constant from there, so there is exactly one refusal path in this
|
|
561
|
+
module and this function does not own a second copy of it. */
|
|
562
|
+
return callerFrom(seen);
|
|
563
|
+
}
|
|
564
|
+
return UNIDENTIFIED;
|
|
565
|
+
}
|
|
566
|
+
|
|
272
567
|
/**
|
|
273
568
|
* The shape of every line this file can ever contain, as a regex, so the walk
|
|
274
569
|
* can assert the whole file against it in one move rather than hunting for
|
package/package.json
CHANGED
|
@@ -1,23 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "af360",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.11",
|
|
4
4
|
"description": "Watches the things you have built - folders, repos and sites - and tells you what needs you. Runs entirely on your own machine.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"author": "Afeleos LLC",
|
|
7
7
|
"homepage": "https://afeleos.com",
|
|
8
|
-
"
|
|
9
|
-
"type": "git",
|
|
10
|
-
"url": "git+https://github.com/Afeleos-LLC/AF360.git"
|
|
11
|
-
},
|
|
12
|
-
"bugs": {
|
|
13
|
-
"url": "https://github.com/Afeleos-LLC/AF360/issues"
|
|
14
|
-
},
|
|
8
|
+
"mcpName": "com.afeleos/af360",
|
|
15
9
|
"keywords": [
|
|
16
10
|
"local-first",
|
|
17
11
|
"projects",
|
|
18
12
|
"git",
|
|
19
13
|
"monitoring",
|
|
20
|
-
"privacy"
|
|
14
|
+
"privacy",
|
|
15
|
+
"mcp",
|
|
16
|
+
"model-context-protocol"
|
|
17
|
+
],
|
|
18
|
+
"os": [
|
|
19
|
+
"win32"
|
|
21
20
|
],
|
|
22
21
|
"bin": {
|
|
23
22
|
"af360": "bin/af360.mjs"
|
|
Binary file
|