@miadi/chronicle-tui 0.3.0 → 0.4.1
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 +41 -21
- package/dist/App.d.ts +14 -5
- package/dist/App.d.ts.map +1 -1
- package/dist/App.js +595 -321
- package/dist/App.js.map +1 -1
- package/dist/actions.d.ts +31 -21
- package/dist/actions.d.ts.map +1 -1
- package/dist/actions.js +62 -44
- package/dist/actions.js.map +1 -1
- package/dist/api.d.ts +58 -30
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +129 -44
- package/dist/api.js.map +1 -1
- package/dist/attention.d.ts +50 -0
- package/dist/attention.d.ts.map +1 -0
- package/dist/attention.js +69 -0
- package/dist/attention.js.map +1 -0
- package/dist/bin.d.ts +2 -1
- package/dist/bin.d.ts.map +1 -1
- package/dist/bin.js +19 -11
- package/dist/bin.js.map +1 -1
- package/dist/data.d.ts +48 -12
- package/dist/data.d.ts.map +1 -1
- package/dist/data.js +124 -24
- package/dist/data.js.map +1 -1
- package/dist/index.d.ts +6 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -4
- package/dist/index.js.map +1 -1
- package/dist/model.d.ts +10 -2
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js +47 -35
- package/dist/model.js.map +1 -1
- package/dist/text.d.ts +23 -0
- package/dist/text.d.ts.map +1 -0
- package/dist/text.js +57 -0
- package/dist/text.js.map +1 -0
- package/package.json +5 -4
package/dist/api.d.ts
CHANGED
|
@@ -1,21 +1,30 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The browser as a known reader of the Miadi app (
|
|
2
|
+
* The browser as a known reader of the Miadi app (jgwill/Miadi#706).
|
|
3
3
|
*
|
|
4
4
|
* Reads that need no one (the catalog, files, search) stay on the local
|
|
5
5
|
* checkout. Anything that depends on who is reading, and every write, goes
|
|
6
|
-
* through the app's own routes
|
|
7
|
-
*
|
|
6
|
+
* through the app's own routes, so the app keeps the one gate it already has
|
|
7
|
+
* (`lib/api-access.ts`, `lib/identity.ts`, `lib/ceremony-access.ts`).
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
* -
|
|
11
|
-
*
|
|
12
|
-
* -
|
|
9
|
+
* Two tokens, each for what it is:
|
|
10
|
+
* - `MIADI_PERSON_TOKEN` is a person. It is the bearer of every read, so a
|
|
11
|
+
* ceremony or circle shows what that person's seat allows and nothing more.
|
|
12
|
+
* - `MIADI_API_TOKEN_WRITER` passes the write gate. It is the bearer of writes,
|
|
13
|
+
* with the person named beside it in `x-miadi-person-token`, the way the app
|
|
14
|
+
* expects an agent acting for someone (`lib/review-ceremony.ts`).
|
|
15
|
+
* Either alone works for what it can do. A token is only ever sent to the app
|
|
16
|
+
* chosen at start, and never over plain http to a host that is not this one.
|
|
13
17
|
*/
|
|
14
18
|
export declare const TOKEN_ENV = "MIADI_API_TOKEN_WRITER";
|
|
19
|
+
export declare const PERSON_TOKEN_ENV = "MIADI_PERSON_TOKEN";
|
|
20
|
+
export declare const PERSON_TOKEN_HEADER = "x-miadi-person-token";
|
|
21
|
+
/** What `--env` may set. Anything else in the file (PATH included) is left alone. */
|
|
22
|
+
export declare const ENV_FILE_KEYS: readonly ["MIADI_API_TOKEN_WRITER", "MIADI_PERSON_TOKEN", "MIADI_CHRONICLE_ROOT", "MIADI_WEB_URL", "MIADI_URL_BASE_INTERNAL", "MIADI_URL_BASE", "MIADI_CHRONICLE_MW_URL"];
|
|
15
23
|
/**
|
|
16
|
-
* Load `KEY=value` lines into the environment: `export`
|
|
17
|
-
* `#` comments are understood, nothing is expanded. A key
|
|
18
|
-
* wins over one already set, since the file was named on purpose.
|
|
24
|
+
* Load the allowed `KEY=value` lines of a file into the environment: `export`
|
|
25
|
+
* prefixes, quotes and `#` comments are understood, nothing is expanded. A key
|
|
26
|
+
* the file sets wins over one already set, since the file was named on purpose.
|
|
27
|
+
* Returns the keys it set.
|
|
19
28
|
*/
|
|
20
29
|
export declare function loadEnvFile(path: string, env?: NodeJS.ProcessEnv): string[];
|
|
21
30
|
export interface Reader {
|
|
@@ -34,34 +43,50 @@ export declare class ApiError extends Error {
|
|
|
34
43
|
readonly code?: string | undefined;
|
|
35
44
|
constructor(message: string, status: number, code?: string | undefined);
|
|
36
45
|
}
|
|
46
|
+
/** A token may travel to https, or to plain http on this machine only. */
|
|
47
|
+
export declare function mayCarryToken(base: string): boolean;
|
|
48
|
+
export interface Tokens {
|
|
49
|
+
writer?: string;
|
|
50
|
+
person?: string;
|
|
51
|
+
}
|
|
37
52
|
export declare class MiadiApi {
|
|
38
53
|
readonly base: string;
|
|
39
|
-
private readonly
|
|
40
|
-
|
|
54
|
+
private readonly tokens;
|
|
55
|
+
/** Set once the app has answered who is reading; false when it refused the token. */
|
|
56
|
+
accepted: boolean | undefined;
|
|
57
|
+
constructor(base: string, tokens?: Tokens);
|
|
58
|
+
/** A token is set (whether or not the app accepted it yet). */
|
|
41
59
|
get signed(): boolean;
|
|
60
|
+
/** A person is named, so seats apply. */
|
|
61
|
+
get asPerson(): boolean;
|
|
62
|
+
/** Writes are offered: a token is set and the app did not refuse it. */
|
|
63
|
+
get mayWrite(): boolean;
|
|
64
|
+
private headers;
|
|
42
65
|
private call;
|
|
43
66
|
get<T>(path: string): Promise<T>;
|
|
44
67
|
post<T>(path: string, body: unknown): Promise<T>;
|
|
68
|
+
/** Who the app says is reading. Marks the client refused on 401 or 403. */
|
|
45
69
|
me(): Promise<Reader | null>;
|
|
70
|
+
/** Would the app record a write from this client? The web room asks the attention door the same. */
|
|
71
|
+
mayAnswer(): Promise<boolean>;
|
|
46
72
|
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
question: string;
|
|
52
|
-
unlocks?: string;
|
|
53
|
-
asked?: string;
|
|
54
|
-
state: "open" | "answered" | string;
|
|
55
|
-
answer: string | null;
|
|
56
|
-
answered_at: string | null;
|
|
57
|
-
episode?: string;
|
|
73
|
+
export interface Connection {
|
|
74
|
+
api: MiadiApi | null;
|
|
75
|
+
/** Why a token was not attached, when one was set. */
|
|
76
|
+
warning?: string;
|
|
58
77
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
78
|
+
/**
|
|
79
|
+
* The app this browser talks to. `--url` wins; otherwise the local app, then
|
|
80
|
+
* the tailnet one (`MIADI_URL_BASE_INTERNAL`). The public front is used only
|
|
81
|
+
* when named with `--url`, so a token never goes there by accident. Probes
|
|
82
|
+
* carry no token.
|
|
83
|
+
*/
|
|
84
|
+
export declare function connectApi(url?: string, env?: NodeJS.ProcessEnv): Promise<Connection>;
|
|
63
85
|
export declare function answerAttention(api: MiadiApi, episode: string, id: string, answer: string): Promise<{
|
|
64
86
|
ok: boolean;
|
|
87
|
+
result?: {
|
|
88
|
+
synchronized?: boolean;
|
|
89
|
+
};
|
|
65
90
|
}>;
|
|
66
91
|
export interface CeremonyCard {
|
|
67
92
|
kind: "ceremony";
|
|
@@ -88,9 +113,9 @@ export interface CircleCard {
|
|
|
88
113
|
can: string[];
|
|
89
114
|
}
|
|
90
115
|
/**
|
|
91
|
-
* What a ceremony shows a reader
|
|
92
|
-
*
|
|
93
|
-
*
|
|
116
|
+
* What a ceremony shows a seated reader: its kind, direction, intention,
|
|
117
|
+
* episode, circle and whether it is closed. Never its turns: those are
|
|
118
|
+
* people's words, read in the circle (jgwill/Miadi#680, D3).
|
|
94
119
|
*/
|
|
95
120
|
export declare function ceremonyCard(api: MiadiApi, id: string): Promise<CeremonyCard>;
|
|
96
121
|
export declare function circleCard(api: MiadiApi, id: string): Promise<CircleCard>;
|
|
@@ -100,5 +125,8 @@ export declare function addReview(api: MiadiApi, episode: string, review: string
|
|
|
100
125
|
title?: string;
|
|
101
126
|
id?: string;
|
|
102
127
|
};
|
|
128
|
+
ceremony?: {
|
|
129
|
+
state?: string;
|
|
130
|
+
};
|
|
103
131
|
}>;
|
|
104
132
|
//# sourceMappingURL=api.d.ts.map
|
package/dist/api.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
|
package/dist/api.js
CHANGED
|
@@ -1,39 +1,57 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The browser as a known reader of the Miadi app (
|
|
2
|
+
* The browser as a known reader of the Miadi app (jgwill/Miadi#706).
|
|
3
3
|
*
|
|
4
4
|
* Reads that need no one (the catalog, files, search) stay on the local
|
|
5
5
|
* checkout. Anything that depends on who is reading, and every write, goes
|
|
6
|
-
* through the app's own routes
|
|
7
|
-
*
|
|
6
|
+
* through the app's own routes, so the app keeps the one gate it already has
|
|
7
|
+
* (`lib/api-access.ts`, `lib/identity.ts`, `lib/ceremony-access.ts`).
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
* -
|
|
11
|
-
*
|
|
12
|
-
* -
|
|
9
|
+
* Two tokens, each for what it is:
|
|
10
|
+
* - `MIADI_PERSON_TOKEN` is a person. It is the bearer of every read, so a
|
|
11
|
+
* ceremony or circle shows what that person's seat allows and nothing more.
|
|
12
|
+
* - `MIADI_API_TOKEN_WRITER` passes the write gate. It is the bearer of writes,
|
|
13
|
+
* with the person named beside it in `x-miadi-person-token`, the way the app
|
|
14
|
+
* expects an agent acting for someone (`lib/review-ceremony.ts`).
|
|
15
|
+
* Either alone works for what it can do. A token is only ever sent to the app
|
|
16
|
+
* chosen at start, and never over plain http to a host that is not this one.
|
|
13
17
|
*/
|
|
14
18
|
import fs from "node:fs";
|
|
15
19
|
import { readWebBases } from "@miadi/inquiry-weave";
|
|
16
20
|
export const TOKEN_ENV = "MIADI_API_TOKEN_WRITER";
|
|
21
|
+
export const PERSON_TOKEN_ENV = "MIADI_PERSON_TOKEN";
|
|
22
|
+
export const PERSON_TOKEN_HEADER = "x-miadi-person-token";
|
|
23
|
+
/** What `--env` may set. Anything else in the file (PATH included) is left alone. */
|
|
24
|
+
export const ENV_FILE_KEYS = [
|
|
25
|
+
TOKEN_ENV,
|
|
26
|
+
PERSON_TOKEN_ENV,
|
|
27
|
+
"MIADI_CHRONICLE_ROOT",
|
|
28
|
+
"MIADI_WEB_URL",
|
|
29
|
+
"MIADI_URL_BASE_INTERNAL",
|
|
30
|
+
"MIADI_URL_BASE",
|
|
31
|
+
"MIADI_CHRONICLE_MW_URL",
|
|
32
|
+
];
|
|
17
33
|
/**
|
|
18
|
-
* Load `KEY=value` lines into the environment: `export`
|
|
19
|
-
* `#` comments are understood, nothing is expanded. A key
|
|
20
|
-
* wins over one already set, since the file was named on purpose.
|
|
34
|
+
* Load the allowed `KEY=value` lines of a file into the environment: `export`
|
|
35
|
+
* prefixes, quotes and `#` comments are understood, nothing is expanded. A key
|
|
36
|
+
* the file sets wins over one already set, since the file was named on purpose.
|
|
37
|
+
* Returns the keys it set.
|
|
21
38
|
*/
|
|
22
39
|
export function loadEnvFile(path, env = process.env) {
|
|
40
|
+
const allowed = new Set(ENV_FILE_KEYS);
|
|
23
41
|
const loaded = [];
|
|
24
42
|
for (const raw of fs.readFileSync(path, "utf8").split(/\r?\n/)) {
|
|
25
43
|
const line = raw.trim();
|
|
26
44
|
if (!line || line.startsWith("#"))
|
|
27
45
|
continue;
|
|
28
46
|
const m = /^(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)$/.exec(line);
|
|
29
|
-
if (!m)
|
|
47
|
+
if (!m || !allowed.has(m[1]))
|
|
30
48
|
continue;
|
|
31
49
|
let value = m[2];
|
|
32
|
-
const quoted = /^(["'])(
|
|
50
|
+
const quoted = /^(["'])(.*?)\1(?:\s+#.*)?$/.exec(value);
|
|
33
51
|
if (quoted)
|
|
34
52
|
value = quoted[2];
|
|
35
53
|
else
|
|
36
|
-
value = value.replace(/\s+#.*$/, "");
|
|
54
|
+
value = value.replace(/\s+#.*$/, "").trim();
|
|
37
55
|
env[m[1]] = value;
|
|
38
56
|
loaded.push(m[1]);
|
|
39
57
|
}
|
|
@@ -48,15 +66,48 @@ export class ApiError extends Error {
|
|
|
48
66
|
this.code = code;
|
|
49
67
|
}
|
|
50
68
|
}
|
|
69
|
+
/** A token may travel to https, or to plain http on this machine only. */
|
|
70
|
+
export function mayCarryToken(base) {
|
|
71
|
+
try {
|
|
72
|
+
const url = new URL(base);
|
|
73
|
+
if (url.protocol === "https:")
|
|
74
|
+
return true;
|
|
75
|
+
return url.protocol === "http:" && ["127.0.0.1", "localhost", "[::1]"].includes(url.hostname);
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
51
81
|
export class MiadiApi {
|
|
52
82
|
base;
|
|
53
|
-
|
|
54
|
-
|
|
83
|
+
tokens;
|
|
84
|
+
/** Set once the app has answered who is reading; false when it refused the token. */
|
|
85
|
+
accepted;
|
|
86
|
+
constructor(base, tokens = {}) {
|
|
55
87
|
this.base = base;
|
|
56
|
-
this.
|
|
88
|
+
this.tokens = tokens;
|
|
57
89
|
}
|
|
90
|
+
/** A token is set (whether or not the app accepted it yet). */
|
|
58
91
|
get signed() {
|
|
59
|
-
return Boolean(this.
|
|
92
|
+
return Boolean(this.tokens.writer || this.tokens.person);
|
|
93
|
+
}
|
|
94
|
+
/** A person is named, so seats apply. */
|
|
95
|
+
get asPerson() {
|
|
96
|
+
return Boolean(this.tokens.person);
|
|
97
|
+
}
|
|
98
|
+
/** Writes are offered: a token is set and the app did not refuse it. */
|
|
99
|
+
get mayWrite() {
|
|
100
|
+
return this.signed && this.accepted !== false;
|
|
101
|
+
}
|
|
102
|
+
headers(write) {
|
|
103
|
+
const { writer, person } = this.tokens;
|
|
104
|
+
const bearer = write ? (writer ?? person) : (person ?? writer);
|
|
105
|
+
const headers = {};
|
|
106
|
+
if (bearer)
|
|
107
|
+
headers.authorization = `Bearer ${bearer}`;
|
|
108
|
+
if (write && writer && person)
|
|
109
|
+
headers[PERSON_TOKEN_HEADER] = person;
|
|
110
|
+
return headers;
|
|
60
111
|
}
|
|
61
112
|
async call(method, path, body) {
|
|
62
113
|
const controller = new AbortController();
|
|
@@ -68,7 +119,7 @@ export class MiadiApi {
|
|
|
68
119
|
headers: {
|
|
69
120
|
accept: "application/json",
|
|
70
121
|
...(body === undefined ? {} : { "content-type": "application/json" }),
|
|
71
|
-
...
|
|
122
|
+
...this.headers(method === "POST"),
|
|
72
123
|
},
|
|
73
124
|
body: body === undefined ? undefined : JSON.stringify(body),
|
|
74
125
|
});
|
|
@@ -96,19 +147,40 @@ export class MiadiApi {
|
|
|
96
147
|
post(path, body) {
|
|
97
148
|
return this.call("POST", path, body);
|
|
98
149
|
}
|
|
150
|
+
/** Who the app says is reading. Marks the client refused on 401 or 403. */
|
|
99
151
|
async me() {
|
|
100
|
-
if (!this.
|
|
152
|
+
if (!this.signed)
|
|
101
153
|
return null;
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
154
|
+
try {
|
|
155
|
+
const me = await this.get("/api/identity/me");
|
|
156
|
+
this.accepted = Boolean(me.person);
|
|
157
|
+
if (!me.person)
|
|
158
|
+
return null;
|
|
159
|
+
return {
|
|
160
|
+
id: me.person.id,
|
|
161
|
+
name: me.person.name,
|
|
162
|
+
role: me.person.role,
|
|
163
|
+
tier: me.api_tier,
|
|
164
|
+
circles: (me.circles ?? []).map((circle) => ({ id: circle.id, name: circle.name })),
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
catch (error) {
|
|
168
|
+
if (error instanceof ApiError && (error.status === 401 || error.status === 403))
|
|
169
|
+
this.accepted = false;
|
|
170
|
+
throw error;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
/** Would the app record a write from this client? The web room asks the attention door the same. */
|
|
174
|
+
async mayAnswer() {
|
|
175
|
+
if (!this.mayWrite)
|
|
176
|
+
return false;
|
|
177
|
+
try {
|
|
178
|
+
const body = await this.call("GET", "/api/chronicle/attention?capabilities=1");
|
|
179
|
+
return body?.capabilities?.answer === true;
|
|
180
|
+
}
|
|
181
|
+
catch {
|
|
182
|
+
return false;
|
|
183
|
+
}
|
|
112
184
|
}
|
|
113
185
|
}
|
|
114
186
|
async function answers(base) {
|
|
@@ -125,42 +197,55 @@ async function answers(base) {
|
|
|
125
197
|
clearTimeout(timer);
|
|
126
198
|
}
|
|
127
199
|
}
|
|
128
|
-
/**
|
|
200
|
+
/**
|
|
201
|
+
* The app this browser talks to. `--url` wins; otherwise the local app, then
|
|
202
|
+
* the tailnet one (`MIADI_URL_BASE_INTERNAL`). The public front is used only
|
|
203
|
+
* when named with `--url`, so a token never goes there by accident. Probes
|
|
204
|
+
* carry no token.
|
|
205
|
+
*/
|
|
129
206
|
export async function connectApi(url, env = process.env) {
|
|
130
|
-
const
|
|
207
|
+
const tokens = {
|
|
208
|
+
writer: env[TOKEN_ENV]?.trim() || undefined,
|
|
209
|
+
person: env[PERSON_TOKEN_ENV]?.trim() || undefined,
|
|
210
|
+
};
|
|
211
|
+
const make = (base) => {
|
|
212
|
+
const clean = base.replace(/\/+$/, "");
|
|
213
|
+
if ((tokens.writer || tokens.person) && !mayCarryToken(clean)) {
|
|
214
|
+
return { api: new MiadiApi(clean), warning: `${clean} is plain http on another host: the token stays home and the app is read-only.` };
|
|
215
|
+
}
|
|
216
|
+
return { api: new MiadiApi(clean, tokens) };
|
|
217
|
+
};
|
|
131
218
|
if (url)
|
|
132
|
-
return
|
|
219
|
+
return make(url);
|
|
133
220
|
const bases = readWebBases(env);
|
|
134
|
-
for (const base of [bases.local, bases.internal
|
|
221
|
+
for (const base of [bases.local, bases.internal]) {
|
|
135
222
|
if (base && (await answers(base.replace(/\/+$/, ""))))
|
|
136
|
-
return
|
|
223
|
+
return make(base);
|
|
137
224
|
}
|
|
138
|
-
return null;
|
|
139
|
-
}
|
|
140
|
-
export async function listAttention(api, episode) {
|
|
141
|
-
const result = await api.get(`/api/chronicle/attention?episode=${encodeURIComponent(episode)}&state=all`);
|
|
142
|
-
return { items: result.items ?? [], canAnswer: Boolean(result.capabilities?.answer) };
|
|
225
|
+
return { api: null };
|
|
143
226
|
}
|
|
227
|
+
// ---------------------------------------------------------------------------
|
|
228
|
+
// The routes the browser uses, typed as the app answers them (checked 2026-10-01)
|
|
229
|
+
// ---------------------------------------------------------------------------
|
|
144
230
|
export function answerAttention(api, episode, id, answer) {
|
|
145
231
|
return api.post("/api/chronicle/attention", { episode, id, answer, expectedState: "open" });
|
|
146
232
|
}
|
|
147
233
|
const trueKeys = (can) => can && typeof can === "object" ? Object.entries(can).filter(([, v]) => v === true).map(([k]) => k) : [];
|
|
148
234
|
/**
|
|
149
|
-
* What a ceremony shows a reader
|
|
150
|
-
*
|
|
151
|
-
*
|
|
235
|
+
* What a ceremony shows a seated reader: its kind, direction, intention,
|
|
236
|
+
* episode, circle and whether it is closed. Never its turns: those are
|
|
237
|
+
* people's words, read in the circle (jgwill/Miadi#680, D3).
|
|
152
238
|
*/
|
|
153
239
|
export async function ceremonyCard(api, id) {
|
|
154
240
|
const view = await api.get(`/api/ceremony/${encodeURIComponent(id)}`);
|
|
155
241
|
const intentions = view.ceremony.intentions;
|
|
156
|
-
const episode = view.episode?.episode_path;
|
|
157
242
|
return {
|
|
158
243
|
kind: "ceremony",
|
|
159
244
|
id: view.ceremony.id,
|
|
160
245
|
type: view.ceremony.type,
|
|
161
246
|
direction: view.ceremony.direction,
|
|
162
247
|
intentions: (Array.isArray(intentions) ? intentions : intentions ? [intentions] : []).map((line) => line.replace(/\s+/g, " ").trim()),
|
|
163
|
-
episode,
|
|
248
|
+
episode: view.episode?.episode_path,
|
|
164
249
|
circle: view.circle?.name,
|
|
165
250
|
closed: Boolean(view.closed),
|
|
166
251
|
can: trueKeys(view.can),
|
package/dist/api.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chronicle ATTENTION in the terminal, as the web room has it (jgwill/Miadi#706).
|
|
3
|
+
*
|
|
4
|
+
* The room shows attention twice: a chronicle-wide board of every open item,
|
|
5
|
+
* newest-asked first, filtered by the same search box as the episodes
|
|
6
|
+
* (`app/chronicle/components/ChronicleAttention.tsx`), and each episode's own
|
|
7
|
+
* panel with Open and History and the cited context of each question
|
|
8
|
+
* (`EpisodeAttention.tsx`). Both are hosts of `@miadi/attention-core`, whose
|
|
9
|
+
* plain functions decide which list shows, what each heading says and whether
|
|
10
|
+
* an answer may be recorded. This module is the terminal's host of the same
|
|
11
|
+
* core: it reads through `@miadi/inquiry-weave` exactly as the app does, and
|
|
12
|
+
* answers through the app's `POST /api/chronicle/attention`.
|
|
13
|
+
*/
|
|
14
|
+
import { type AttentionPanelLabels, type AttentionView } from "@miadi/attention-core";
|
|
15
|
+
import { type ChronicleAttentionItem } from "@miadi/inquiry-weave";
|
|
16
|
+
export type { AttentionView };
|
|
17
|
+
export type BoardItem = ChronicleAttentionItem;
|
|
18
|
+
/** The board's words, as the web room's board says them. */
|
|
19
|
+
export declare const BOARD_LABELS: Required<AttentionPanelLabels>;
|
|
20
|
+
/** One episode's panel keeps the core's own words. */
|
|
21
|
+
export declare const ROOM_LABELS: Required<AttentionPanelLabels>;
|
|
22
|
+
export declare function readOnlyLabel(tokenEnv: string): string;
|
|
23
|
+
/** Every open item across the chronicle, newest-asked first: what the board lists. */
|
|
24
|
+
export declare function loadBoard(root: string): Promise<BoardItem[]>;
|
|
25
|
+
export interface EpisodePanel {
|
|
26
|
+
episode: string;
|
|
27
|
+
items: BoardItem[];
|
|
28
|
+
parseError?: string;
|
|
29
|
+
}
|
|
30
|
+
/** One episode's items with the cited context of each, as the room reads them. */
|
|
31
|
+
export declare function loadEpisodePanel(root: string, episode: string): Promise<EpisodePanel>;
|
|
32
|
+
/** The board answers the episode search box: question, episode and what it unlocks. */
|
|
33
|
+
export declare function filterBoard(items: readonly BoardItem[], query: string): BoardItem[];
|
|
34
|
+
/** The list a panel shows, and its heading, decided by the core. */
|
|
35
|
+
export declare function panelView(items: readonly BoardItem[], selected: AttentionView, labels: Required<AttentionPanelLabels>, parseError?: string): {
|
|
36
|
+
view: AttentionView;
|
|
37
|
+
shown: BoardItem[];
|
|
38
|
+
heading: string;
|
|
39
|
+
meta: string;
|
|
40
|
+
};
|
|
41
|
+
/** Check an answer the way every host checks it, before anything is sent. */
|
|
42
|
+
export declare function checkAnswer(draft: string, maxLength?: number): import("@miadi/attention-core").AnswerValidation;
|
|
43
|
+
/** What the room says once an answer is recorded: the wheel is reported, never assumed. */
|
|
44
|
+
export declare function answeredMessage(result: {
|
|
45
|
+
synchronized?: boolean;
|
|
46
|
+
} | undefined): {
|
|
47
|
+
tone: "ok" | "warn";
|
|
48
|
+
message: string;
|
|
49
|
+
};
|
|
50
|
+
//# sourceMappingURL=attention.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attention.d.ts","sourceRoot":"","sources":["../src/attention.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAQL,KAAK,oBAAoB,EACzB,KAAK,aAAa,EACnB,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EAGL,KAAK,sBAAsB,EAC5B,MAAM,sBAAsB,CAAA;AAE7B,YAAY,EAAE,aAAa,EAAE,CAAA;AAC7B,MAAM,MAAM,SAAS,GAAG,sBAAsB,CAAA;AAE9C,4DAA4D;AAC5D,eAAO,MAAM,YAAY,gCAKvB,CAAA;AAEF,sDAAsD;AACtD,eAAO,MAAM,WAAW,gCAAkB,CAAA;AAE1C,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED,sFAAsF;AACtF,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAGlE;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,SAAS,EAAE,CAAA;IAClB,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,kFAAkF;AAClF,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAG3F;AAED,uFAAuF;AACvF,wBAAgB,WAAW,CAAC,KAAK,EAAE,SAAS,SAAS,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,CAOnF;AAED,oEAAoE;AACpE,wBAAgB,SAAS,CACvB,KAAK,EAAE,SAAS,SAAS,EAAE,EAC3B,QAAQ,EAAE,aAAa,EACvB,MAAM,EAAE,QAAQ,CAAC,oBAAoB,CAAC,EACtC,UAAU,CAAC,EAAE,MAAM,GAClB;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,KAAK,EAAE,SAAS,EAAE,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAS5E;AAED,6EAA6E;AAC7E,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,SAA4B,oDAE/E;AAED,2FAA2F;AAC3F,wBAAgB,eAAe,CAAC,MAAM,EAAE;IAAE,YAAY,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,SAAS,GAAG;IAAE,IAAI,EAAE,IAAI,GAAG,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAIxH"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chronicle ATTENTION in the terminal, as the web room has it (jgwill/Miadi#706).
|
|
3
|
+
*
|
|
4
|
+
* The room shows attention twice: a chronicle-wide board of every open item,
|
|
5
|
+
* newest-asked first, filtered by the same search box as the episodes
|
|
6
|
+
* (`app/chronicle/components/ChronicleAttention.tsx`), and each episode's own
|
|
7
|
+
* panel with Open and History and the cited context of each question
|
|
8
|
+
* (`EpisodeAttention.tsx`). Both are hosts of `@miadi/attention-core`, whose
|
|
9
|
+
* plain functions decide which list shows, what each heading says and whether
|
|
10
|
+
* an answer may be recorded. This module is the terminal's host of the same
|
|
11
|
+
* core: it reads through `@miadi/inquiry-weave` exactly as the app does, and
|
|
12
|
+
* answers through the app's `POST /api/chronicle/attention`.
|
|
13
|
+
*/
|
|
14
|
+
import { DEFAULT_ANSWER_MAX_LENGTH, headingMeta, headingText, partitionItems, resolveLabels, resolveView, validateAnswer, } from "@miadi/attention-core";
|
|
15
|
+
import { listChronicleAttention, readEpisodeAttention, } from "@miadi/inquiry-weave";
|
|
16
|
+
/** The board's words, as the web room's board says them. */
|
|
17
|
+
export const BOARD_LABELS = resolveLabels({
|
|
18
|
+
title: "Needs your attention",
|
|
19
|
+
completeTitle: "Nothing waits on you",
|
|
20
|
+
openSuffix: "newest first — answer one here, or open its room",
|
|
21
|
+
completeSuffix: "decisions recorded across the chronicle",
|
|
22
|
+
});
|
|
23
|
+
/** One episode's panel keeps the core's own words. */
|
|
24
|
+
export const ROOM_LABELS = resolveLabels();
|
|
25
|
+
export function readOnlyLabel(tokenEnv) {
|
|
26
|
+
return `View only — answering needs the Miadi app and ${tokenEnv} or MIADI_PERSON_TOKEN (or --env <file>).`;
|
|
27
|
+
}
|
|
28
|
+
/** Every open item across the chronicle, newest-asked first: what the board lists. */
|
|
29
|
+
export async function loadBoard(root) {
|
|
30
|
+
const items = await listChronicleAttention(root, { state: "open" });
|
|
31
|
+
return items.filter((item) => item.state === "open");
|
|
32
|
+
}
|
|
33
|
+
/** One episode's items with the cited context of each, as the room reads them. */
|
|
34
|
+
export async function loadEpisodePanel(root, episode) {
|
|
35
|
+
const attention = await readEpisodeAttention(root, episode, { includeContext: true });
|
|
36
|
+
return { episode, items: attention?.items ?? [], parseError: attention?.parseError };
|
|
37
|
+
}
|
|
38
|
+
/** The board answers the episode search box: question, episode and what it unlocks. */
|
|
39
|
+
export function filterBoard(items, query) {
|
|
40
|
+
const words = query.toLowerCase().split(/\s+/).filter(Boolean);
|
|
41
|
+
if (words.length === 0)
|
|
42
|
+
return [...items];
|
|
43
|
+
return items.filter((item) => {
|
|
44
|
+
const haystack = [item.question, item.episode, item.unlocks, item.id].filter(Boolean).join(" ").toLowerCase();
|
|
45
|
+
return words.every((word) => haystack.includes(word));
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
/** The list a panel shows, and its heading, decided by the core. */
|
|
49
|
+
export function panelView(items, selected, labels, parseError) {
|
|
50
|
+
const { open, answered } = partitionItems(items);
|
|
51
|
+
const view = resolveView(selected, open.length, answered.length);
|
|
52
|
+
return {
|
|
53
|
+
view,
|
|
54
|
+
shown: view === "history" ? answered : view === "open" ? open : [],
|
|
55
|
+
heading: headingText(open.length > 0, labels),
|
|
56
|
+
meta: headingMeta({ parseError, openCount: open.length, answeredCount: answered.length, labels }),
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
/** Check an answer the way every host checks it, before anything is sent. */
|
|
60
|
+
export function checkAnswer(draft, maxLength = DEFAULT_ANSWER_MAX_LENGTH) {
|
|
61
|
+
return validateAnswer(draft, ROOM_LABELS, maxLength);
|
|
62
|
+
}
|
|
63
|
+
/** What the room says once an answer is recorded: the wheel is reported, never assumed. */
|
|
64
|
+
export function answeredMessage(result) {
|
|
65
|
+
return result?.synchronized === true
|
|
66
|
+
? { tone: "ok", message: "Answer recorded in the episode and verified on the wheel." }
|
|
67
|
+
: { tone: "warn", message: "Answer recorded in the episode; the wheel projection is pending." };
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=attention.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attention.js","sourceRoot":"","sources":["../src/attention.ts"],"names":[],"mappings":"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"}
|
package/dist/bin.d.ts
CHANGED
|
@@ -7,7 +7,8 @@
|
|
|
7
7
|
* miadi-chronicle 352 open on one episode (number, ep352 or folder name)
|
|
8
8
|
* miadi-chronicle --search "talking circle" open in full-text mode
|
|
9
9
|
* miadi-chronicle --filter review open with a title filter
|
|
10
|
-
* miadi-chronicle --env ~/.env.miadi load
|
|
10
|
+
* miadi-chronicle --env ~/.env.miadi load the tokens, the root and the app's address first
|
|
11
|
+
* miadi-chronicle --attention open on the chronicle's attention board
|
|
11
12
|
* miadi-chronicle --url https://miadi.tail3b11eb.ts.net act through this app
|
|
12
13
|
*
|
|
13
14
|
* Exit codes: 0 ok, 2 usage (no root, no terminal).
|
package/dist/bin.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bin.d.ts","sourceRoot":"","sources":["../src/bin.tsx"],"names":[],"mappings":";AACA
|
|
1
|
+
{"version":3,"file":"bin.d.ts","sourceRoot":"","sources":["../src/bin.tsx"],"names":[],"mappings":";AACA;;;;;;;;;;;;;GAaG"}
|