@miadi/webweave 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +68 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/session.d.ts +107 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +151 -0
- package/dist/session.js.map +1 -0
- package/package.json +47 -0
package/README.md
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# `@miadi/webweave`
|
|
2
|
+
|
|
3
|
+
TypeScript facade over **Miadi Webweave** — the terminal↔Simplenote bridge.
|
|
4
|
+
|
|
5
|
+
Miadi Webweave puts Simplenote notes under terminal control. Simplenote has no public API, so the Python package drives a real Chrome over CDP/Playwright and reads and writes notes as if there were one. A note becomes an *address that follows you to every device* — the cheapest shared surface between a human at a terminal, a human on a phone, and an agent.
|
|
6
|
+
|
|
7
|
+
This package is the typed boundary. The implementation is [`miadi-webweave`](https://pypi.org/project/miadi-webweave/) on PyPI.
|
|
8
|
+
|
|
9
|
+
## What it wraps
|
|
10
|
+
|
|
11
|
+
**One operation: resolving the active session.**
|
|
12
|
+
|
|
13
|
+
Webweave sessions are directory-based. The CLI finds the active session by looking for `.miadi/webweave/session.json` in the current directory, then walking up through parents, then `$HOME`. Every platform surface needs that answer — *is there a session here, and what is it?* — before it can do anything with a note.
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import { resolveSession, sessionInfo, hasSession } from "@miadi/webweave"
|
|
17
|
+
|
|
18
|
+
// Typed read, no subprocess, no browser.
|
|
19
|
+
const resolved = resolveSession(process.cwd())
|
|
20
|
+
if (resolved) {
|
|
21
|
+
console.log(resolved.session.session_id, resolved.sessionRoot)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Defer to the installed CLI for the verdict, get typed data alongside it.
|
|
25
|
+
const info = await sessionInfo({ cwd: process.cwd() })
|
|
26
|
+
console.log(info.ok, info.session?.session_id)
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
| Export | Purpose |
|
|
30
|
+
|---|---|
|
|
31
|
+
| `resolveSession(dir?)` | Walk up for `session.json`; returns `ResolvedSession \| null` |
|
|
32
|
+
| `hasSession(dir?)` | Boolean form |
|
|
33
|
+
| `sessionInfo(opts?)` | Runs `miadi-webweave session info`; returns its verdict **and** the typed record |
|
|
34
|
+
| `sessionSearchPath(dir?)` | The candidate paths, nearest first — useful for diagnostics |
|
|
35
|
+
| `WebweaveSession` | The record as written by the Python package |
|
|
36
|
+
|
|
37
|
+
### Design notes
|
|
38
|
+
|
|
39
|
+
- **Field names stay snake_case.** They are read verbatim from `session.json`; renaming them here would silently diverge from the file on disk. Unknown keys are preserved, so a newer Python version passing through does not lose data.
|
|
40
|
+
- **`session info` has no `--json` flag**, so its stdout is returned unparsed rather than scraped. Screen-scraping a human-formatted banner breaks on the next cosmetic change. The CLI supplies the verdict; the state file supplies the typed data. When they disagree, both are reported rather than reconciled.
|
|
41
|
+
- **A missing binary throws** instead of reporting "no session" — a setup fault and an empty directory are different conditions.
|
|
42
|
+
- **A malformed or unreadable `session.json` throws.** Only a genuine absence returns `null`.
|
|
43
|
+
|
|
44
|
+
## What it does not wrap, and why
|
|
45
|
+
|
|
46
|
+
**No `read`, no `write`.** Those need note-id → URL resolution, which does not exist in the Python package yet.
|
|
47
|
+
|
|
48
|
+
Our records store a note address as a bare 32-hex id (e.g. `weave_id: a2c4150ced044cffaa0cd1ab58c516b2`) or as `simplenote://note/<id>`. The Python side accepts neither: every call site either hardcodes `https://app.simplenote.com/` or expects the `/p/<token>` *publish* form. Passing a bare id to `read` reaches Chrome and then fails with `Cannot navigate to invalid URL`, and `https://app.simplenote.com/note/<id>` returns **404** — so the resolution is a lookup nobody has written.
|
|
49
|
+
|
|
50
|
+
The identifier we store is not an identifier the tool consumes. That belongs in `miadi_webweave`, not here: fixing it in a facade would repair it for one consumer and leave the CLI, the 35 MCP tools, and every future caller broken. Tracked in `jgwill/Miadi#562`.
|
|
51
|
+
|
|
52
|
+
A facade with one working verb is a package. A facade with five unproven ones is a promise.
|
|
53
|
+
|
|
54
|
+
## Requirements
|
|
55
|
+
|
|
56
|
+
- Node ≥ 20
|
|
57
|
+
- `miadi-webweave >= 0.7.0` for `sessionInfo()` — `pip install "miadi-webweave>=0.7.0"`
|
|
58
|
+
|
|
59
|
+
`resolveSession()` and `hasSession()` need no Python at all; they read the state file directly.
|
|
60
|
+
|
|
61
|
+
## Build and test
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
npm run build
|
|
65
|
+
npm test
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Verified against the published `miadi-webweave 0.7.0` installed from PyPI: the facade's typed read and the CLI's exit status agree on a directory with a session, on a nested directory (both walk up to the same root), and on a directory without one.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@miadi/webweave` — TypeScript facade over Miadi Webweave.
|
|
3
|
+
*
|
|
4
|
+
* Wraps one operation that works today: resolving the active webweave session
|
|
5
|
+
* for a directory. That is the primitive every platform surface needs before it
|
|
6
|
+
* can do anything with a note.
|
|
7
|
+
*
|
|
8
|
+
* The Python package (`miadi-webweave`, PyPI 0.7.0) is the implementation; this
|
|
9
|
+
* package is the typed boundary. Read and write are deliberately absent — they
|
|
10
|
+
* require note-id -> URL resolution, which the Python side does not implement yet.
|
|
11
|
+
*/
|
|
12
|
+
export { SESSION_RELATIVE_PATH, WebweaveSessionError, hasSession, resolveSession, sessionInfo, sessionSearchPath, } from "./session.js";
|
|
13
|
+
export type { FourDirections, ResolvedSession, SessionInfoOptions, SessionInfoResult, WebweaveSession, } from "./session.js";
|
|
14
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EACL,qBAAqB,EACrB,oBAAoB,EACpB,UAAU,EACV,cAAc,EACd,WAAW,EACX,iBAAiB,GAClB,MAAM,cAAc,CAAA;AAErB,YAAY,EACV,cAAc,EACd,eAAe,EACf,kBAAkB,EAClB,iBAAiB,EACjB,eAAe,GAChB,MAAM,cAAc,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@miadi/webweave` — TypeScript facade over Miadi Webweave.
|
|
3
|
+
*
|
|
4
|
+
* Wraps one operation that works today: resolving the active webweave session
|
|
5
|
+
* for a directory. That is the primitive every platform surface needs before it
|
|
6
|
+
* can do anything with a note.
|
|
7
|
+
*
|
|
8
|
+
* The Python package (`miadi-webweave`, PyPI 0.7.0) is the implementation; this
|
|
9
|
+
* package is the typed boundary. Read and write are deliberately absent — they
|
|
10
|
+
* require note-id -> URL resolution, which the Python side does not implement yet.
|
|
11
|
+
*/
|
|
12
|
+
export { SESSION_RELATIVE_PATH, WebweaveSessionError, hasSession, resolveSession, sessionInfo, sessionSearchPath, } from "./session.js";
|
|
13
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EACL,qBAAqB,EACrB,oBAAoB,EACpB,UAAU,EACV,cAAc,EACd,WAAW,EACX,iBAAiB,GAClB,MAAM,cAAc,CAAA"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session resolution — the one verb this facade wraps.
|
|
3
|
+
*
|
|
4
|
+
* Miadi Webweave sessions are directory-based. The Python CLI (miadi-webweave
|
|
5
|
+
* >= 0.7.0) locates the active session by looking for `.miadi/webweave/session.json`
|
|
6
|
+
* in the current directory, then walking up through parents, then the home
|
|
7
|
+
* directory. This module mirrors that rule in TypeScript and, when asked, defers
|
|
8
|
+
* to the CLI itself as the authority.
|
|
9
|
+
*
|
|
10
|
+
* Deliberately narrow: no note reading, no note writing, no browser. Those verbs
|
|
11
|
+
* need note-id -> URL resolution, which does not exist in the Python package yet
|
|
12
|
+
* (`https://app.simplenote.com/note/<id>` returns 404). This facade wraps what
|
|
13
|
+
* works and says nothing about what does not.
|
|
14
|
+
*/
|
|
15
|
+
/** Relative location of the session record inside a session directory. */
|
|
16
|
+
export declare const SESSION_RELATIVE_PATH: string;
|
|
17
|
+
/** Per-direction session state, present when a session was started with an intention. */
|
|
18
|
+
export interface FourDirections {
|
|
19
|
+
east?: Record<string, unknown>;
|
|
20
|
+
south?: Record<string, unknown>;
|
|
21
|
+
west?: Record<string, unknown>;
|
|
22
|
+
north?: Record<string, unknown>;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* The session record as written by miadi-webweave.
|
|
26
|
+
*
|
|
27
|
+
* Field names are snake_case because they are read verbatim from the Python
|
|
28
|
+
* package's `session.json`; renaming them here would silently diverge from the
|
|
29
|
+
* file on disk. Unknown keys are preserved via the index signature rather than
|
|
30
|
+
* dropped, so a newer Python version does not lose data passing through here.
|
|
31
|
+
*/
|
|
32
|
+
export interface WebweaveSession {
|
|
33
|
+
session_id: string;
|
|
34
|
+
search_key?: string;
|
|
35
|
+
ai_assistant?: string;
|
|
36
|
+
issue_number?: number;
|
|
37
|
+
repository?: string;
|
|
38
|
+
cdp_endpoint?: string;
|
|
39
|
+
created_at?: string;
|
|
40
|
+
four_directions?: FourDirections;
|
|
41
|
+
[key: string]: unknown;
|
|
42
|
+
}
|
|
43
|
+
/** Where a session was found, and what it contains. */
|
|
44
|
+
export interface ResolvedSession {
|
|
45
|
+
/** Absolute path to the `session.json` that was read. */
|
|
46
|
+
sessionFile: string;
|
|
47
|
+
/** Absolute path to the directory owning the session (the parent of `.miadi/`). */
|
|
48
|
+
sessionRoot: string;
|
|
49
|
+
/** The directory resolution started from. */
|
|
50
|
+
searchedFrom: string;
|
|
51
|
+
session: WebweaveSession;
|
|
52
|
+
}
|
|
53
|
+
export declare class WebweaveSessionError extends Error {
|
|
54
|
+
readonly cause?: unknown | undefined;
|
|
55
|
+
constructor(message: string, cause?: unknown | undefined);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Candidate session files for a starting directory, nearest first.
|
|
59
|
+
*
|
|
60
|
+
* Ordering mirrors the CLI: the directory itself, each parent up to the
|
|
61
|
+
* filesystem root, then the home directory. Home is appended only when it was
|
|
62
|
+
* not already visited, so it is never probed twice.
|
|
63
|
+
*/
|
|
64
|
+
export declare function sessionSearchPath(startDir?: string): string[];
|
|
65
|
+
/**
|
|
66
|
+
* Resolve the active session by reading the state file directly.
|
|
67
|
+
*
|
|
68
|
+
* Returns `null` when no session file exists anywhere on the search path — the
|
|
69
|
+
* same condition under which the CLI exits 1. Throws only when a session file
|
|
70
|
+
* exists but cannot be used, because an unreadable or malformed session is a
|
|
71
|
+
* real fault and must not be reported as "no session".
|
|
72
|
+
*/
|
|
73
|
+
export declare function resolveSession(startDir?: string): ResolvedSession | null;
|
|
74
|
+
/** True when a session resolves for the given directory. */
|
|
75
|
+
export declare function hasSession(startDir?: string): boolean;
|
|
76
|
+
export interface SessionInfoOptions {
|
|
77
|
+
/** Directory to resolve from. Defaults to the current working directory. */
|
|
78
|
+
cwd?: string;
|
|
79
|
+
/** Path or name of the CLI. Defaults to `miadi-webweave` on PATH. */
|
|
80
|
+
bin?: string;
|
|
81
|
+
/** Milliseconds before the CLI call is abandoned. Defaults to 30000. */
|
|
82
|
+
timeoutMs?: number;
|
|
83
|
+
}
|
|
84
|
+
export interface SessionInfoResult {
|
|
85
|
+
/** True when the CLI reported an active session (exit 0). */
|
|
86
|
+
ok: boolean;
|
|
87
|
+
/** Exit code returned by the CLI. */
|
|
88
|
+
exitCode: number;
|
|
89
|
+
/** The CLI's stdout, verbatim — it is human-formatted, not machine-readable. */
|
|
90
|
+
stdout: string;
|
|
91
|
+
stderr: string;
|
|
92
|
+
/** The session as read from disk, so callers get typed data alongside the CLI's verdict. */
|
|
93
|
+
session: WebweaveSession | null;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Ask the installed CLI whether a session is active, and read the record.
|
|
97
|
+
*
|
|
98
|
+
* `miadi-webweave session info` exposes no `--json` flag, so its stdout is
|
|
99
|
+
* returned unparsed rather than scraped — screen-scraping a human-formatted
|
|
100
|
+
* banner would break on the next cosmetic change. The typed session comes from
|
|
101
|
+
* the state file; the CLI supplies the verdict. When they disagree, that is a
|
|
102
|
+
* real signal and both are reported rather than reconciled here.
|
|
103
|
+
*
|
|
104
|
+
* Requires the Python package `miadi-webweave >= 0.7.0` on PATH.
|
|
105
|
+
*/
|
|
106
|
+
export declare function sessionInfo(options?: SessionInfoOptions): Promise<SessionInfoResult>;
|
|
107
|
+
//# sourceMappingURL=session.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAUH,0EAA0E;AAC1E,eAAO,MAAM,qBAAqB,QAA6C,CAAA;AAE/E,yFAAyF;AACzF,MAAM,WAAW,cAAc;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAChC;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAA;IAClB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,eAAe,CAAC,EAAE,cAAc,CAAA;IAChC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CACvB;AAED,uDAAuD;AACvD,MAAM,WAAW,eAAe;IAC9B,yDAAyD;IACzD,WAAW,EAAE,MAAM,CAAA;IACnB,mFAAmF;IACnF,WAAW,EAAE,MAAM,CAAA;IACnB,6CAA6C;IAC7C,YAAY,EAAE,MAAM,CAAA;IACpB,OAAO,EAAE,eAAe,CAAA;CACzB;AAED,qBAAa,oBAAqB,SAAQ,KAAK;IAChB,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO;gBAAzC,OAAO,EAAE,MAAM,EAAW,KAAK,CAAC,EAAE,OAAO,YAAA;CAItD;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,GAAE,MAAsB,GAAG,MAAM,EAAE,CAsB5E;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,QAAQ,GAAE,MAAsB,GAAG,eAAe,GAAG,IAAI,CAwCvF;AAED,4DAA4D;AAC5D,wBAAgB,UAAU,CAAC,QAAQ,GAAE,MAAsB,GAAG,OAAO,CAEpE;AAED,MAAM,WAAW,kBAAkB;IACjC,4EAA4E;IAC5E,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,qEAAqE;IACrE,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,wEAAwE;IACxE,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,MAAM,WAAW,iBAAiB;IAChC,6DAA6D;IAC7D,EAAE,EAAE,OAAO,CAAA;IACX,qCAAqC;IACrC,QAAQ,EAAE,MAAM,CAAA;IAChB,gFAAgF;IAChF,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,4FAA4F;IAC5F,OAAO,EAAE,eAAe,GAAG,IAAI,CAAA;CAChC;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,WAAW,CAAC,OAAO,GAAE,kBAAuB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAoC9F"}
|
package/dist/session.js
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session resolution — the one verb this facade wraps.
|
|
3
|
+
*
|
|
4
|
+
* Miadi Webweave sessions are directory-based. The Python CLI (miadi-webweave
|
|
5
|
+
* >= 0.7.0) locates the active session by looking for `.miadi/webweave/session.json`
|
|
6
|
+
* in the current directory, then walking up through parents, then the home
|
|
7
|
+
* directory. This module mirrors that rule in TypeScript and, when asked, defers
|
|
8
|
+
* to the CLI itself as the authority.
|
|
9
|
+
*
|
|
10
|
+
* Deliberately narrow: no note reading, no note writing, no browser. Those verbs
|
|
11
|
+
* need note-id -> URL resolution, which does not exist in the Python package yet
|
|
12
|
+
* (`https://app.simplenote.com/note/<id>` returns 404). This facade wraps what
|
|
13
|
+
* works and says nothing about what does not.
|
|
14
|
+
*/
|
|
15
|
+
import { execFile } from "node:child_process";
|
|
16
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
17
|
+
import { homedir } from "node:os";
|
|
18
|
+
import { dirname, join, parse as parsePath, resolve } from "node:path";
|
|
19
|
+
import { promisify } from "node:util";
|
|
20
|
+
const execFileAsync = promisify(execFile);
|
|
21
|
+
/** Relative location of the session record inside a session directory. */
|
|
22
|
+
export const SESSION_RELATIVE_PATH = join(".miadi", "webweave", "session.json");
|
|
23
|
+
export class WebweaveSessionError extends Error {
|
|
24
|
+
cause;
|
|
25
|
+
constructor(message, cause) {
|
|
26
|
+
super(message);
|
|
27
|
+
this.cause = cause;
|
|
28
|
+
this.name = "WebweaveSessionError";
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Candidate session files for a starting directory, nearest first.
|
|
33
|
+
*
|
|
34
|
+
* Ordering mirrors the CLI: the directory itself, each parent up to the
|
|
35
|
+
* filesystem root, then the home directory. Home is appended only when it was
|
|
36
|
+
* not already visited, so it is never probed twice.
|
|
37
|
+
*/
|
|
38
|
+
export function sessionSearchPath(startDir = process.cwd()) {
|
|
39
|
+
const start = resolve(startDir);
|
|
40
|
+
const { root } = parsePath(start);
|
|
41
|
+
const candidates = [];
|
|
42
|
+
const seen = new Set();
|
|
43
|
+
let current = start;
|
|
44
|
+
for (;;) {
|
|
45
|
+
if (!seen.has(current)) {
|
|
46
|
+
seen.add(current);
|
|
47
|
+
candidates.push(join(current, SESSION_RELATIVE_PATH));
|
|
48
|
+
}
|
|
49
|
+
if (current === root)
|
|
50
|
+
break;
|
|
51
|
+
const parent = dirname(current);
|
|
52
|
+
if (parent === current)
|
|
53
|
+
break;
|
|
54
|
+
current = parent;
|
|
55
|
+
}
|
|
56
|
+
const home = resolve(homedir());
|
|
57
|
+
if (!seen.has(home))
|
|
58
|
+
candidates.push(join(home, SESSION_RELATIVE_PATH));
|
|
59
|
+
return candidates;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Resolve the active session by reading the state file directly.
|
|
63
|
+
*
|
|
64
|
+
* Returns `null` when no session file exists anywhere on the search path — the
|
|
65
|
+
* same condition under which the CLI exits 1. Throws only when a session file
|
|
66
|
+
* exists but cannot be used, because an unreadable or malformed session is a
|
|
67
|
+
* real fault and must not be reported as "no session".
|
|
68
|
+
*/
|
|
69
|
+
export function resolveSession(startDir = process.cwd()) {
|
|
70
|
+
const searchedFrom = resolve(startDir);
|
|
71
|
+
for (const sessionFile of sessionSearchPath(searchedFrom)) {
|
|
72
|
+
if (!existsSync(sessionFile))
|
|
73
|
+
continue;
|
|
74
|
+
let raw;
|
|
75
|
+
try {
|
|
76
|
+
raw = readFileSync(sessionFile, "utf8");
|
|
77
|
+
}
|
|
78
|
+
catch (cause) {
|
|
79
|
+
throw new WebweaveSessionError(`Session file is not readable: ${sessionFile}`, cause);
|
|
80
|
+
}
|
|
81
|
+
let parsed;
|
|
82
|
+
try {
|
|
83
|
+
parsed = JSON.parse(raw);
|
|
84
|
+
}
|
|
85
|
+
catch (cause) {
|
|
86
|
+
throw new WebweaveSessionError(`Session file is not valid JSON: ${sessionFile}`, cause);
|
|
87
|
+
}
|
|
88
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
89
|
+
throw new WebweaveSessionError(`Session file is not a JSON object: ${sessionFile}`);
|
|
90
|
+
}
|
|
91
|
+
const session = parsed;
|
|
92
|
+
if (typeof session.session_id !== "string" || session.session_id.length === 0) {
|
|
93
|
+
throw new WebweaveSessionError(`Session file has no session_id: ${sessionFile}`);
|
|
94
|
+
}
|
|
95
|
+
// sessionRoot is the directory containing `.miadi/`, i.e. three levels up
|
|
96
|
+
// from `<root>/.miadi/webweave/session.json`.
|
|
97
|
+
return {
|
|
98
|
+
sessionFile,
|
|
99
|
+
sessionRoot: dirname(dirname(dirname(sessionFile))),
|
|
100
|
+
searchedFrom,
|
|
101
|
+
session,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
/** True when a session resolves for the given directory. */
|
|
107
|
+
export function hasSession(startDir = process.cwd()) {
|
|
108
|
+
return resolveSession(startDir) !== null;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Ask the installed CLI whether a session is active, and read the record.
|
|
112
|
+
*
|
|
113
|
+
* `miadi-webweave session info` exposes no `--json` flag, so its stdout is
|
|
114
|
+
* returned unparsed rather than scraped — screen-scraping a human-formatted
|
|
115
|
+
* banner would break on the next cosmetic change. The typed session comes from
|
|
116
|
+
* the state file; the CLI supplies the verdict. When they disagree, that is a
|
|
117
|
+
* real signal and both are reported rather than reconciled here.
|
|
118
|
+
*
|
|
119
|
+
* Requires the Python package `miadi-webweave >= 0.7.0` on PATH.
|
|
120
|
+
*/
|
|
121
|
+
export async function sessionInfo(options = {}) {
|
|
122
|
+
const cwd = resolve(options.cwd ?? process.cwd());
|
|
123
|
+
const bin = options.bin ?? "miadi-webweave";
|
|
124
|
+
const timeout = options.timeoutMs ?? 30_000;
|
|
125
|
+
let stdout = "";
|
|
126
|
+
let stderr = "";
|
|
127
|
+
let exitCode = 0;
|
|
128
|
+
try {
|
|
129
|
+
const result = await execFileAsync(bin, ["session", "info"], { cwd, timeout, encoding: "utf8" });
|
|
130
|
+
stdout = result.stdout;
|
|
131
|
+
stderr = result.stderr;
|
|
132
|
+
}
|
|
133
|
+
catch (error) {
|
|
134
|
+
const err = error;
|
|
135
|
+
// A missing binary is a setup fault, not "no session" — surface it.
|
|
136
|
+
if (err.code === "ENOENT") {
|
|
137
|
+
throw new WebweaveSessionError(`Miadi Webweave CLI not found: ${bin}. Install it with: pip install "miadi-webweave>=0.7.0"`, error);
|
|
138
|
+
}
|
|
139
|
+
stdout = err.stdout ?? "";
|
|
140
|
+
stderr = err.stderr ?? "";
|
|
141
|
+
exitCode = typeof err.code === "number" ? err.code : 1;
|
|
142
|
+
}
|
|
143
|
+
return {
|
|
144
|
+
ok: exitCode === 0,
|
|
145
|
+
exitCode,
|
|
146
|
+
stdout,
|
|
147
|
+
stderr,
|
|
148
|
+
session: resolveSession(cwd)?.session ?? null,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@miadi/webweave",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "TypeScript facade over Miadi Webweave. Resolves the active webweave session for a directory — the primitive every platform surface needs before it can read or write a note.",
|
|
5
|
+
"publishConfig": {
|
|
6
|
+
"access": "public"
|
|
7
|
+
},
|
|
8
|
+
"type": "module",
|
|
9
|
+
"main": "./dist/index.js",
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"import": "./dist/index.js"
|
|
15
|
+
},
|
|
16
|
+
"./package.json": "./package.json"
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"dist",
|
|
20
|
+
"README.md"
|
|
21
|
+
],
|
|
22
|
+
"scripts": {
|
|
23
|
+
"build": "../../node_modules/.bin/tsc -p tsconfig.build.json",
|
|
24
|
+
"test": "npm run build && node --test test/*.test.mjs",
|
|
25
|
+
"prepublishOnly": "npm run build"
|
|
26
|
+
},
|
|
27
|
+
"keywords": [
|
|
28
|
+
"miadi",
|
|
29
|
+
"webweave",
|
|
30
|
+
"simplenote",
|
|
31
|
+
"session"
|
|
32
|
+
],
|
|
33
|
+
"author": "Guillaume D. Isabelle",
|
|
34
|
+
"license": "MIT",
|
|
35
|
+
"engines": {
|
|
36
|
+
"node": ">=20"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@types/node": "^22",
|
|
40
|
+
"typescript": "^5.4.0"
|
|
41
|
+
},
|
|
42
|
+
"peerDependenciesMeta": {
|
|
43
|
+
"miadi-webweave": {
|
|
44
|
+
"optional": true
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|