@mulmoclaude/core 0.23.0 → 0.23.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/assets/helps/collection-skills.md +12 -4
- package/assets/helps/custom-view.md +13 -9
- package/assets/skills-preset/mc-zenn/SKILL.md +31 -0
- package/dist/collection/registry/server/index.cjs +1 -1
- package/dist/collection/registry/server/index.js +1 -1
- package/dist/collection/server/csvQuery.d.ts +13 -5
- package/dist/collection/server/csvStore.d.ts +2 -0
- package/dist/collection/server/index.cjs +3 -1
- package/dist/collection/server/index.d.ts +2 -1
- package/dist/collection/server/index.js +2 -2
- package/dist/collection/server/jsonlQuery.d.ts +4 -0
- package/dist/collection-watchers/index.cjs +1 -1
- package/dist/collection-watchers/index.js +1 -1
- package/dist/feeds/server/index.cjs +1 -1
- package/dist/feeds/server/index.js +1 -1
- package/dist/google/auth.d.ts +10 -1
- package/dist/google/authFlow.d.ts +1 -0
- package/dist/google/index.cjs +79 -38
- package/dist/google/index.cjs.map +1 -1
- package/dist/google/index.d.ts +1 -1
- package/dist/google/index.js +78 -39
- package/dist/google/index.js.map +1 -1
- package/dist/{server--FgDORd3.js → server-D2ibbixF.js} +113 -19
- package/dist/server-D2ibbixF.js.map +1 -0
- package/dist/{server-Q7ld-FlZ.cjs → server-Jaogu3Ky.cjs} +124 -18
- package/dist/server-Jaogu3Ky.cjs.map +1 -0
- package/package.json +1 -1
- package/dist/server--FgDORd3.js.map +0 -1
- package/dist/server-Q7ld-FlZ.cjs.map +0 -1
|
@@ -854,6 +854,13 @@ records through **`manageCollection`**, not raw file I/O:
|
|
|
854
854
|
/ `fields` on large collections to keep the result small — e.g.
|
|
855
855
|
`fields: ["id"]` to check for an id collision before an add.
|
|
856
856
|
- **Delete** — remove the record file (`manageCollection` has no delete).
|
|
857
|
+
- **Aggregate — `queryItems`.** Counts, sums, averages, group-bys on ANY
|
|
858
|
+
collection via a structured query (`groupBy` / `aggregates` / `where` /
|
|
859
|
+
`orderBy` / `limit` — full shape in the "External data (CSV) collections"
|
|
860
|
+
section below). On file-backed collections it aggregates the ENRICHED
|
|
861
|
+
records, so computed fields (`derived` / `rollup` / `toggle`) are
|
|
862
|
+
queryable columns — "sum of invoice totals" works even when `total` is a
|
|
863
|
+
formula. Prefer it over doing arithmetic on `getItems` output.
|
|
857
864
|
- **Cross-collection questions — `getOntology`.** Returns every collection in
|
|
858
865
|
the workspace with its `primaryKey`, effective `displayField`, record count,
|
|
859
866
|
and its `ref` / `embed` / `backlinks` / `rollup` relations (field → related slug, including refs
|
|
@@ -961,10 +968,11 @@ Semantics to remember (and to tell the user):
|
|
|
961
968
|
logged). Fine for browsing — but NEVER compute an aggregate from
|
|
962
969
|
`getItems` output on a large file (a capped scan gives a silently wrong
|
|
963
970
|
number). Use `queryItems` instead.
|
|
964
|
-
- **Aggregation — `manageCollection` `queryItems
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
971
|
+
- **Aggregation — `manageCollection` `queryItems`**: a structured query over
|
|
972
|
+
the WHOLE file (uncapped scan, DuckDB underneath). Answer counts / sums /
|
|
973
|
+
averages / group-bys with it — don't shell out to python/pandas for
|
|
974
|
+
questions it covers. (It works on EVERY collection — see the Records
|
|
975
|
+
section; this bullet is about the dataSource specifics.) Shape:
|
|
968
976
|
|
|
969
977
|
```json
|
|
970
978
|
{
|
|
@@ -101,12 +101,14 @@ toggles, embeds) — the same numbers the user sees elsewhere.
|
|
|
101
101
|
/ shows one record at a time. Combinable with `fields`.
|
|
102
102
|
- The primary key is always returned regardless of `fields`.
|
|
103
103
|
|
|
104
|
-
### Aggregation queries (
|
|
104
|
+
### Aggregation queries (`read` capability)
|
|
105
105
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
106
|
+
A view can run structured aggregations over the collection — on a
|
|
107
|
+
`dataSource` (CSV) collection this scans the WHOLE file (the record read
|
|
108
|
+
above is row-capped at 5,000 there, so an aggregate computed from it would
|
|
109
|
+
be silently wrong); on a file-backed collection it aggregates the ENRICHED
|
|
110
|
+
records, so computed fields (`derived` / `rollup` / `toggle`) are queryable
|
|
111
|
+
columns:
|
|
110
112
|
|
|
111
113
|
```js
|
|
112
114
|
const res = await fetch(dataUrl + "/query", {
|
|
@@ -130,10 +132,12 @@ const { rows } = await res.json(); // [{ Category, total, n }, ...] — chart th
|
|
|
130
132
|
`groupBy`/`aggregates`; `orderBy` sorts by a groupBy column or an
|
|
131
133
|
aggregate alias; result rows clamp at 1,000 by default.
|
|
132
134
|
- Structured JSON only — there is **no SQL surface**, by design.
|
|
133
|
-
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
135
|
+
- Combine with `onChange` (below) to stay live: in the callback, re-run
|
|
136
|
+
**this POST query** (wrap it in your own `refresh()` and register that)
|
|
137
|
+
— NOT the `?fields=` record read from the section above, which would
|
|
138
|
+
silently repaint an aggregation view with non-aggregated data. A
|
|
139
|
+
replaced CSV or edited records then redraw the chart — that's a live
|
|
140
|
+
dashboard.
|
|
137
141
|
|
|
138
142
|
### Writing records (only with the `write` capability)
|
|
139
143
|
|
|
@@ -43,9 +43,11 @@ unless the user already told you:
|
|
|
43
43
|
|
|
44
44
|
- **Clone an existing Zenn repo** (they already write Zenn on GitHub). Get the
|
|
45
45
|
repo URL, then:
|
|
46
|
+
|
|
46
47
|
```bash
|
|
47
48
|
git clone <url> github/zenn
|
|
48
49
|
```
|
|
50
|
+
|
|
49
51
|
`npx zenn` fetches zenn-cli on demand, so a missing local dependency is fine.
|
|
50
52
|
|
|
51
53
|
- **Create a fresh project** (standard zenn-cli flow):
|
|
@@ -90,6 +92,7 @@ fill it in. **A published slug becomes the article URL and can't change** — pi
|
|
|
90
92
|
it deliberately.
|
|
91
93
|
|
|
92
94
|
**Step 3 — write the frontmatter** (Zenn house style):
|
|
95
|
+
|
|
93
96
|
```yaml
|
|
94
97
|
---
|
|
95
98
|
title: "<a clear title, in the user's language>"
|
|
@@ -99,6 +102,7 @@ topics: ["MulmoClaude", "<related>"]
|
|
|
99
102
|
published: true
|
|
100
103
|
---
|
|
101
104
|
```
|
|
105
|
+
|
|
102
106
|
- **Always include `MulmoClaude` in `topics`.** At most 5 topics, no spaces
|
|
103
107
|
inside a single topic.
|
|
104
108
|
- `type` defaults to `tech`; `published` defaults to `true` (use `false` when
|
|
@@ -109,6 +113,33 @@ implementation (fenced ` ```lang ` blocks, runnable commands) → result → a s
|
|
|
109
113
|
wrap-up. Informative but casual; describe the work, not yourself. Put images in
|
|
110
114
|
`github/zenn/images/` and reference them as ``.
|
|
111
115
|
|
|
116
|
+
Write it the way a person would, not the way a model defaults to. Each rule
|
|
117
|
+
below comes from real reader feedback — ignore them and the draft reads as
|
|
118
|
+
machine output:
|
|
119
|
+
|
|
120
|
+
- **Sound human, not like a generated listicle.** Prefer flowing prose over
|
|
121
|
+
walls of bullets, use bold sparingly, and let paragraphs connect into an
|
|
122
|
+
argument. If every section is just a heading plus a list, vary the rhythm.
|
|
123
|
+
- **No uncommon loanwords or jargon.** Use only terms a typical reader already
|
|
124
|
+
knows. Niche English acronyms, trendy katakana, and insider slang either get
|
|
125
|
+
dropped or replaced with plain words. A term the field itself hasn't settled
|
|
126
|
+
on ("code smell" and the like) is a red flag — say the plain thing instead
|
|
127
|
+
("code that works now but bites you later").
|
|
128
|
+
- **Define every term and acronym on first use**, in plain language, and put the
|
|
129
|
+
foundational ones up front — define "DRY" before the article leans on it. A
|
|
130
|
+
reader should never hit a word they can't parse.
|
|
131
|
+
- **Carry a source's essence, don't just cite it.** When an idea comes from a
|
|
132
|
+
book or article, explain the idea itself in your own words; "see <book>"
|
|
133
|
+
teaches nothing. Search for the actual content when you're unsure what it says,
|
|
134
|
+
then write the substance.
|
|
135
|
+
- **Make the article self-contained.** Anything project-specific — a repo's
|
|
136
|
+
internals, a config choice, a domain constraint — needs enough general
|
|
137
|
+
background that a reader with zero context can follow. Running longer is fine
|
|
138
|
+
when the extra length buys understanding.
|
|
139
|
+
- **Match the stated audience.** "Explain to intermediate developers" means
|
|
140
|
+
patient explanations, concrete examples, real code from the work, and links —
|
|
141
|
+
not a terse summary.
|
|
142
|
+
|
|
112
143
|
**Step 5 — save + preview.** Write `github/zenn/articles/<slug>.md`. Tell the
|
|
113
144
|
user the path and how to preview: `cd github/zenn && npx zenn preview`
|
|
114
145
|
(http://localhost:8000). Surface the title, slug, and topics.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_rolldown_runtime = require("../../../rolldown-runtime-D6vf50IK.cjs");
|
|
3
|
-
const require_server = require("../../../server-
|
|
3
|
+
const require_server = require("../../../server-Jaogu3Ky.cjs");
|
|
4
4
|
const require_collection_paths = require("../../paths.cjs");
|
|
5
5
|
const require_skill_bridge_index = require("../../../skill-bridge/index.cjs");
|
|
6
6
|
const require_types = require("../../../types-CNqkLT4M.cjs");
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { D as CollectionSchemaZ, S as acceptParsedSchema, _ as errorMessage,
|
|
1
|
+
import { D as CollectionSchemaZ, S as acceptParsedSchema, _ as errorMessage, _t as collectionsRegistriesConfigPath, bt as log, ct as writeFileAtomic, g as ONE_SECOND_MS, ht as safeRecordId, w as loadCollection } from "../../../server-D2ibbixF.js";
|
|
2
2
|
import { isSafeActionTemplatePath } from "../../paths.js";
|
|
3
3
|
import { claudeSkillDir, dataSkillDir, mirrorSkillWrite } from "../../../skill-bridge/index.js";
|
|
4
4
|
import { n as parseRegistryIndex, r as isRecord, t as OFFICIAL_REGISTRY_NAME } from "../../../types-BKVZrtyc.js";
|
|
@@ -8,12 +8,20 @@ export declare function quoteLiteral(value: string): string;
|
|
|
8
8
|
* DuckDB's sniffer turns `001` into BIGINT 1, so leading zeros vanish
|
|
9
9
|
* and distinct keys collapse. */
|
|
10
10
|
export declare function readCsvArgs(primaryKey: string): string;
|
|
11
|
-
/** Compile a
|
|
12
|
-
* the CSV path — the executor binds it) and the where-value parameters
|
|
13
|
-
* that follow it. Callers MUST have run `CollectionQueryZ` first; this
|
|
14
|
-
* function trusts the shape (aliases already charset-checked, orderBy
|
|
15
|
-
* membership already enforced). */
|
|
11
|
+
/** Compile against a CSV file (the dataSource store's engine). */
|
|
16
12
|
export declare function compileCsvQuery(query: CollectionQuery, primaryKey: string): {
|
|
17
13
|
sql: string;
|
|
18
14
|
params: unknown[];
|
|
19
15
|
};
|
|
16
|
+
/** Compile against a JSONL file of ENRICHED records — the file-backed
|
|
17
|
+
* collections' engine (see `jsonlQuery.ts`). No VARCHAR key pin needed:
|
|
18
|
+
* enriched record ids are already strings. `sample_size=-1` makes the
|
|
19
|
+
* schema inference scan EVERY line — with the default sample, a sparse
|
|
20
|
+
* optional/derived field first appearing past the sample would not be
|
|
21
|
+
* inferred as a column and the query would binder-error on it (Codex P2
|
|
22
|
+
* on #2165). The full scan costs nothing extra here: aggregation reads
|
|
23
|
+
* the whole file anyway. */
|
|
24
|
+
export declare function compileJsonlQuery(query: CollectionQuery): {
|
|
25
|
+
sql: string;
|
|
26
|
+
params: unknown[];
|
|
27
|
+
};
|
|
@@ -30,6 +30,8 @@ export declare function dedupeByRecordId(items: CollectionItem[], primaryKey: st
|
|
|
30
30
|
items: CollectionItem[];
|
|
31
31
|
duplicates: number;
|
|
32
32
|
};
|
|
33
|
+
export declare function cacheDir(): string;
|
|
34
|
+
export declare function queryCsv(sql: string, params: unknown[]): Promise<Record<string, unknown>[]>;
|
|
33
35
|
/** Every row of the CSV as records — capped, deduped, id-encoded. The
|
|
34
36
|
* key column is pinned to VARCHAR (see `readCsvArgs`). `workspaceRoot`
|
|
35
37
|
* drives the per-read containment check; omitted, the configured host
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_promptSafety = require("../../promptSafety-DRd15gQ6.cjs");
|
|
3
|
-
const require_server = require("../../server-
|
|
3
|
+
const require_server = require("../../server-Jaogu3Ky.cjs");
|
|
4
4
|
const require_collection_paths = require("../paths.cjs");
|
|
5
5
|
exports.COMPUTED_TYPES = require_promptSafety.COMPUTED_TYPES;
|
|
6
6
|
exports.CollectionQueryZ = require_server.CollectionQueryZ;
|
|
@@ -19,6 +19,7 @@ exports.buildCollectionActionSeedPrompt = require_server.buildCollectionActionSe
|
|
|
19
19
|
exports.buildWorkspaceOntology = require_server.buildWorkspaceOntology;
|
|
20
20
|
exports.collectionWritable = require_server.collectionWritable;
|
|
21
21
|
exports.compileCsvQuery = require_server.compileCsvQuery;
|
|
22
|
+
exports.compileJsonlQuery = require_server.compileJsonlQuery;
|
|
22
23
|
exports.compileRecordZ = require_server.compileRecordZ;
|
|
23
24
|
exports.computeCollectionIcon = require_server.computeCollectionIcon;
|
|
24
25
|
exports.computeSuccessor = require_server.computeSuccessor;
|
|
@@ -66,6 +67,7 @@ exports.resolveCreateItemId = require_server.resolveCreateItemId;
|
|
|
66
67
|
exports.resolveDataDir = require_server.resolveDataDir;
|
|
67
68
|
exports.resolveEvery = require_server.resolveEvery;
|
|
68
69
|
exports.resolveTemplatePath = require_server.resolveTemplatePath;
|
|
70
|
+
exports.runQueryOverRows = require_server.runQueryOverRows;
|
|
69
71
|
exports.safeRecordId = require_server.safeRecordId;
|
|
70
72
|
exports.safeSlugName = require_server.safeSlugName;
|
|
71
73
|
exports.schemaRelations = require_server.schemaRelations;
|
|
@@ -5,7 +5,8 @@ export * from './templatePath';
|
|
|
5
5
|
export * from './io';
|
|
6
6
|
export * from './store';
|
|
7
7
|
export { MAX_CSV_ROWS, encodeCsvRecordId, decodeCsvRecordId, normalizeCsvValue, csvRowToItem, dedupeByRecordId } from './csvStore';
|
|
8
|
-
export { compileCsvQuery } from './csvQuery';
|
|
8
|
+
export { compileCsvQuery, compileJsonlQuery } from './csvQuery';
|
|
9
|
+
export { runQueryOverRows } from './jsonlQuery';
|
|
9
10
|
export { CollectionQueryZ, MAX_QUERY_ROWS, DEFAULT_QUERY_ROWS } from '../core/queryZ';
|
|
10
11
|
export type { CollectionQuery, CollectionQueryAggregate, CollectionQueryOrder, CollectionQueryWhere } from '../core/queryZ';
|
|
11
12
|
export * from './validate';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { I as COMPUTED_TYPES } from "../../promptSafety-rDWA9_JS.js";
|
|
2
|
-
import { $ as
|
|
2
|
+
import { $ as isRegularFile, A as validateCollectionRecords, B as decodeCsvRecordId, C as discoverCollections, D as CollectionSchemaZ, E as toSummary, F as collectionWritable, G as compileJsonlQuery, H as encodeCsvRecordId, I as readOnlyRefusal, J as MAX_QUERY_ROWS, K as CollectionQueryZ, L as storeFor, M as compileRecordZ, N as recordFieldProblem, O as applyMutateAction, P as runQueryOverRows, Q as generateItemId, R as MAX_CSV_ROWS, S as acceptParsedSchema, St as setCollectionChangePublisher, T as toDetail, U as normalizeCsvValue, V as dedupeByRecordId, W as compileCsvQuery, X as buildCollectionActionSeedPrompt, Y as buildActionSeedPrompt, Z as deleteItem, a as deleteCollection, at as readSkillTemplate, b as buildWorkspaceOntology, bt as log, c as computeSuccessor, d as isTriggerDue, dt as isContainedInWorkspace, et as listItems, f as maybeSpawnSuccessor, ft as itemFilePath, gt as safeSlugName, h as successorId, ht as safeRecordId, i as deleteCustomView, it as readItem, j as validateRecordObject, k as firstMutateParamProblem, l as daysInMonth, lt as SCHEMA_FILE, m as resolveEvery, mt as resolveTemplatePath, n as MAX_UNSELECTIVE_ITEMS, nt as readCustomViewHtml, o as deleteCollectionRefusalMessage, ot as resolveCreateItemId, p as parseCivil, pt as resolveDataDir, q as DEFAULT_QUERY_ROWS, r as makeManageCollectionTool, rt as readCustomViewI18n, s as advanceTriggerDate, st as writeItem, t as MAX_SCHEMA_ISSUES, tt as promptPathsFor, u as formatCivil, ut as isContainedInRoot, v as computeCollectionIcon, vt as configureCollectionHost, w as loadCollection, x as schemaRelations, xt as publishCollectionChange, y as enrichItems, yt as getWorkspaceRoot, z as csvRowToItem } from "../../server-D2ibbixF.js";
|
|
3
3
|
import { isSafeActionTemplatePath, isSafeCustomViewI18nPath, isSafeCustomViewPath, isSafeTemplatePath } from "../paths.js";
|
|
4
|
-
export { COMPUTED_TYPES, CollectionQueryZ, CollectionSchemaZ, DEFAULT_QUERY_ROWS, MAX_CSV_ROWS, MAX_QUERY_ROWS, MAX_SCHEMA_ISSUES, MAX_UNSELECTIVE_ITEMS, SCHEMA_FILE, acceptParsedSchema, advanceTriggerDate, applyMutateAction, buildActionSeedPrompt, buildCollectionActionSeedPrompt, buildWorkspaceOntology, collectionWritable, compileCsvQuery, compileRecordZ, computeCollectionIcon, computeSuccessor, configureCollectionHost, csvRowToItem, daysInMonth, decodeCsvRecordId, dedupeByRecordId, deleteCollection, deleteCollectionRefusalMessage, deleteCustomView, deleteItem, discoverCollections, encodeCsvRecordId, enrichItems, firstMutateParamProblem, formatCivil, generateItemId, getWorkspaceRoot, isContainedInRoot, isContainedInWorkspace, isRegularFile, isSafeActionTemplatePath, isSafeCustomViewI18nPath, isSafeCustomViewPath, isSafeTemplatePath, isTriggerDue, itemFilePath, listItems, loadCollection, log, makeManageCollectionTool, maybeSpawnSuccessor, normalizeCsvValue, parseCivil, promptPathsFor, publishCollectionChange, readCustomViewHtml, readCustomViewI18n, readItem, readOnlyRefusal, readSkillTemplate, recordFieldProblem, resolveCreateItemId, resolveDataDir, resolveEvery, resolveTemplatePath, safeRecordId, safeSlugName, schemaRelations, setCollectionChangePublisher, storeFor, successorId, toDetail, toSummary, validateCollectionRecords, validateRecordObject, writeItem };
|
|
4
|
+
export { COMPUTED_TYPES, CollectionQueryZ, CollectionSchemaZ, DEFAULT_QUERY_ROWS, MAX_CSV_ROWS, MAX_QUERY_ROWS, MAX_SCHEMA_ISSUES, MAX_UNSELECTIVE_ITEMS, SCHEMA_FILE, acceptParsedSchema, advanceTriggerDate, applyMutateAction, buildActionSeedPrompt, buildCollectionActionSeedPrompt, buildWorkspaceOntology, collectionWritable, compileCsvQuery, compileJsonlQuery, compileRecordZ, computeCollectionIcon, computeSuccessor, configureCollectionHost, csvRowToItem, daysInMonth, decodeCsvRecordId, dedupeByRecordId, deleteCollection, deleteCollectionRefusalMessage, deleteCustomView, deleteItem, discoverCollections, encodeCsvRecordId, enrichItems, firstMutateParamProblem, formatCivil, generateItemId, getWorkspaceRoot, isContainedInRoot, isContainedInWorkspace, isRegularFile, isSafeActionTemplatePath, isSafeCustomViewI18nPath, isSafeCustomViewPath, isSafeTemplatePath, isTriggerDue, itemFilePath, listItems, loadCollection, log, makeManageCollectionTool, maybeSpawnSuccessor, normalizeCsvValue, parseCivil, promptPathsFor, publishCollectionChange, readCustomViewHtml, readCustomViewI18n, readItem, readOnlyRefusal, readSkillTemplate, recordFieldProblem, resolveCreateItemId, resolveDataDir, resolveEvery, resolveTemplatePath, runQueryOverRows, safeRecordId, safeSlugName, schemaRelations, setCollectionChangePublisher, storeFor, successorId, toDetail, toSummary, validateCollectionRecords, validateRecordObject, writeItem };
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { CollectionItem } from '../core/schema';
|
|
2
|
+
import { CollectionQuery } from '../core/queryZ';
|
|
3
|
+
/** Run a validated query over enriched collection rows. */
|
|
4
|
+
export declare function runQueryOverRows(rows: CollectionItem[], query: CollectionQuery): Promise<Record<string, unknown>[]>;
|
|
@@ -2,7 +2,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
|
2
2
|
const require_rolldown_runtime = require("../rolldown-runtime-D6vf50IK.cjs");
|
|
3
3
|
const require_promptSafety = require("../promptSafety-DRd15gQ6.cjs");
|
|
4
4
|
require("../collection/index.cjs");
|
|
5
|
-
const require_server = require("../server-
|
|
5
|
+
const require_server = require("../server-Jaogu3Ky.cjs");
|
|
6
6
|
const require_notifier = require("../notifier-bS8IEeLA.cjs");
|
|
7
7
|
let node_path = require("node:path");
|
|
8
8
|
node_path = require_rolldown_runtime.__toESM(node_path, 1);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { A as whenMatches } from "../promptSafety-rDWA9_JS.js";
|
|
2
2
|
import "../collection/index.js";
|
|
3
|
-
import { C as discoverCollections,
|
|
3
|
+
import { C as discoverCollections, d as isTriggerDue, et as listItems, f as maybeSpawnSuccessor, it as readItem, w as loadCollection, xt as publishCollectionChange } from "../server-D2ibbixF.js";
|
|
4
4
|
import { d as publish, m as updateForPlugin, n as clear, s as listAll } from "../notifier-ChpY0XrY.js";
|
|
5
5
|
import path from "node:path";
|
|
6
6
|
import { watch } from "node:fs";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_rolldown_runtime = require("../../rolldown-runtime-D6vf50IK.cjs");
|
|
3
3
|
const require_promptSafety = require("../../promptSafety-DRd15gQ6.cjs");
|
|
4
|
-
const require_server = require("../../server-
|
|
4
|
+
const require_server = require("../../server-Jaogu3Ky.cjs");
|
|
5
5
|
const require_ingestTypes = require("../../ingestTypes-Cev9q77C.cjs");
|
|
6
6
|
const require_feeds_paths = require("../paths.cjs");
|
|
7
7
|
const require_notifier = require("../../notifier-bS8IEeLA.cjs");
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { L as FEED_SCHEDULES, R as INGEST_KINDS } from "../../promptSafety-rDWA9_JS.js";
|
|
2
|
-
import {
|
|
2
|
+
import { C as discoverCollections, X as buildCollectionActionSeedPrompt, Z as deleteItem, at as readSkillTemplate, et as listItems, gt as safeSlugName, pt as resolveDataDir, st as writeItem, tt as promptPathsFor } from "../../server-D2ibbixF.js";
|
|
3
3
|
import { n as DEFAULT_FEED_MAX_ITEMS, r as isFeedSchedule, t as AGENT_INGEST_KIND } from "../../ingestTypes-B-dXxUF9.js";
|
|
4
4
|
import { FEEDS_DIR, feedDir, feedStatePath, feedsRoot, ingestStateDir, ingestStatePath } from "../paths.js";
|
|
5
5
|
import { d as publish, n as clear } from "../../notifier-ChpY0XrY.js";
|
package/dist/google/auth.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { default as http } from 'node:http';
|
|
2
2
|
import { Credentials } from 'google-auth-library';
|
|
3
3
|
import { fetchWithTimeout } from './fetch.js';
|
|
4
|
+
import { IssuedVia } from './tokenStore.js';
|
|
4
5
|
export declare const GOOGLE_CALENDAR_SCOPE = "https://www.googleapis.com/auth/calendar.events";
|
|
5
6
|
/** Minimal read scope for the calendar list + per-calendar colours.
|
|
6
7
|
* `calendar.events` already covers reading/writing events on any calendar, but
|
|
@@ -19,6 +20,9 @@ export interface AuthorizeGoogleOptions {
|
|
|
19
20
|
/** Called with the consent URL; open it in a browser (and/or print it). */
|
|
20
21
|
onAuthUrl?: (url: string) => void;
|
|
21
22
|
timeoutMs?: number;
|
|
23
|
+
/** Abort a still-pending consent (a settings-UI restart, an explicit cancel).
|
|
24
|
+
* Rejects the flow with {@link GOOGLE_AUTH_CANCELLED} and closes the loopback. */
|
|
25
|
+
signal?: AbortSignal;
|
|
22
26
|
}
|
|
23
27
|
export declare function getGoogleAccessToken(home?: string): Promise<string>;
|
|
24
28
|
/** The revoke POST, injectable for tests. */
|
|
@@ -28,5 +32,10 @@ export type RevokeFetch = typeof fetchWithTimeout;
|
|
|
28
32
|
* already consider the token invalid, and keeping the file would leave the
|
|
29
33
|
* user unable to unlink. */
|
|
30
34
|
export declare function unlinkGoogle(home?: string, revokeFetch?: RevokeFetch): Promise<void>;
|
|
31
|
-
|
|
35
|
+
/** Reject reason when a pending flow is torn down (a settings-UI restart or an
|
|
36
|
+
* explicit cancel), kept distinct from a real authorization error so callers
|
|
37
|
+
* can treat it as "user changed their mind", not "linking failed". */
|
|
38
|
+
export declare const GOOGLE_AUTH_CANCELLED = "authorization cancelled";
|
|
39
|
+
export declare const waitForAuthCode: (server: http.Server, expectedState: string, timeoutMs: number, signal?: AbortSignal) => Promise<string>;
|
|
40
|
+
export declare const commitLinkedTokens: (tokens: Credentials, issuedVia: IssuedVia, opts: AuthorizeGoogleOptions) => Promise<Credentials>;
|
|
32
41
|
export declare function authorizeGoogle(opts?: AuthorizeGoogleOptions): Promise<Credentials>;
|
package/dist/google/index.cjs
CHANGED
|
@@ -453,29 +453,50 @@ var respondHtml = (res, status, message) => {
|
|
|
453
453
|
res.writeHead(status, { "Content-Type": "text/html; charset=utf-8" });
|
|
454
454
|
res.end(`<html><body><h3>${message}</h3></body></html>`);
|
|
455
455
|
};
|
|
456
|
-
|
|
456
|
+
/** Reject reason when a pending flow is torn down (a settings-UI restart or an
|
|
457
|
+
* explicit cancel), kept distinct from a real authorization error so callers
|
|
458
|
+
* can treat it as "user changed their mind", not "linking failed". */
|
|
459
|
+
var GOOGLE_AUTH_CANCELLED = "authorization cancelled";
|
|
460
|
+
var handleCallbackRequest = (req, res, expectedState, settle) => {
|
|
461
|
+
const url = new URL(req.url ?? "/", "http://127.0.0.1");
|
|
462
|
+
if (url.pathname !== CALLBACK_PATH) {
|
|
463
|
+
res.writeHead(404);
|
|
464
|
+
res.end();
|
|
465
|
+
return;
|
|
466
|
+
}
|
|
467
|
+
if (url.searchParams.get("state") !== expectedState) {
|
|
468
|
+
respondHtml(res, 400, "Invalid authorization callback. You can close this tab.");
|
|
469
|
+
return;
|
|
470
|
+
}
|
|
471
|
+
try {
|
|
472
|
+
const code = authCodeFromCallback(url, expectedState);
|
|
473
|
+
respondHtml(res, 200, "Authorization complete — you can close this tab.");
|
|
474
|
+
settle.resolve(code);
|
|
475
|
+
} catch (err) {
|
|
476
|
+
respondHtml(res, 400, "Authorization failed — see the terminal for details. You can close this tab.");
|
|
477
|
+
settle.reject(err);
|
|
478
|
+
}
|
|
479
|
+
};
|
|
480
|
+
var waitForAuthCode = (server, expectedState, timeoutMs, signal) => new Promise((resolve, reject) => {
|
|
457
481
|
const timer = setTimeout(() => reject(/* @__PURE__ */ new Error(`authorization timed out after ${timeoutMs / ONE_SECOND_MS}s`)), timeoutMs);
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
482
|
+
const settle = {
|
|
483
|
+
resolve: (code) => {
|
|
484
|
+
clearTimeout(timer);
|
|
485
|
+
resolve(code);
|
|
486
|
+
},
|
|
487
|
+
reject: (err) => {
|
|
488
|
+
clearTimeout(timer);
|
|
489
|
+
reject(err instanceof Error ? err : new Error(String(err)));
|
|
464
490
|
}
|
|
465
|
-
|
|
466
|
-
|
|
491
|
+
};
|
|
492
|
+
if (signal) {
|
|
493
|
+
if (signal.aborted) {
|
|
494
|
+
settle.reject(/* @__PURE__ */ new Error(GOOGLE_AUTH_CANCELLED));
|
|
467
495
|
return;
|
|
468
496
|
}
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
respondHtml(res, 200, "Authorization complete — you can close this tab.");
|
|
473
|
-
resolve(code);
|
|
474
|
-
} catch (err) {
|
|
475
|
-
respondHtml(res, 400, "Authorization failed — see the terminal for details. You can close this tab.");
|
|
476
|
-
reject(err);
|
|
477
|
-
}
|
|
478
|
-
});
|
|
497
|
+
signal.addEventListener("abort", () => settle.reject(/* @__PURE__ */ new Error(GOOGLE_AUTH_CANCELLED)), { once: true });
|
|
498
|
+
}
|
|
499
|
+
server.on("request", (req, res) => handleCallbackRequest(req, res, expectedState, settle));
|
|
479
500
|
});
|
|
480
501
|
var buildConsentUrl = (client, codeChallenge, state) => client.generateAuthUrl({
|
|
481
502
|
access_type: "offline",
|
|
@@ -499,7 +520,7 @@ var authorizeWithLocalClient = async (secret, server, port, opts) => {
|
|
|
499
520
|
if (!codeChallenge) throw new Error("failed to derive a PKCE code challenge");
|
|
500
521
|
const state = (0, node_crypto.randomBytes)(STATE_BYTES).toString("hex");
|
|
501
522
|
opts.onAuthUrl?.(buildConsentUrl(client, codeChallenge, state));
|
|
502
|
-
const code = await waitForAuthCode(server, state, opts.timeoutMs ?? AUTH_TIMEOUT_MS);
|
|
523
|
+
const code = await waitForAuthCode(server, state, opts.timeoutMs ?? AUTH_TIMEOUT_MS, opts.signal);
|
|
503
524
|
const { tokens } = await client.getToken({
|
|
504
525
|
code,
|
|
505
526
|
codeVerifier
|
|
@@ -512,11 +533,18 @@ var authorizeWithBroker = async (server, port, opts) => {
|
|
|
512
533
|
const { authUrl, state } = await brokerStart(port, codeChallenge);
|
|
513
534
|
opts.onAuthUrl?.(authUrl);
|
|
514
535
|
return await brokerExchange({
|
|
515
|
-
code: await waitForAuthCode(server, state, opts.timeoutMs ?? AUTH_TIMEOUT_MS),
|
|
536
|
+
code: await waitForAuthCode(server, state, opts.timeoutMs ?? AUTH_TIMEOUT_MS, opts.signal),
|
|
516
537
|
state,
|
|
517
538
|
codeVerifier
|
|
518
539
|
});
|
|
519
540
|
};
|
|
541
|
+
var commitLinkedTokens = async (tokens, issuedVia, opts) => {
|
|
542
|
+
if (opts.signal?.aborted) throw new Error(GOOGLE_AUTH_CANCELLED);
|
|
543
|
+
return await saveGoogleTokens({
|
|
544
|
+
...tokens,
|
|
545
|
+
issuedVia
|
|
546
|
+
}, opts.home);
|
|
547
|
+
};
|
|
520
548
|
async function authorizeGoogle(opts = {}) {
|
|
521
549
|
const presence = await clientSecretPresence(opts.home);
|
|
522
550
|
if (presence === "ambiguous") await loadClientSecret(opts.home);
|
|
@@ -524,10 +552,7 @@ async function authorizeGoogle(opts = {}) {
|
|
|
524
552
|
const { server, port } = await startLoopbackServer();
|
|
525
553
|
try {
|
|
526
554
|
const issuedVia = useLocalClient ? "local" : "broker";
|
|
527
|
-
return await
|
|
528
|
-
...useLocalClient ? await authorizeWithLocalClient(await loadClientSecret(opts.home), server, port, opts) : await authorizeWithBroker(server, port, opts),
|
|
529
|
-
issuedVia
|
|
530
|
-
}, opts.home);
|
|
555
|
+
return await commitLinkedTokens(useLocalClient ? await authorizeWithLocalClient(await loadClientSecret(opts.home), server, port, opts) : await authorizeWithBroker(server, port, opts), issuedVia, opts);
|
|
531
556
|
} finally {
|
|
532
557
|
server.close();
|
|
533
558
|
}
|
|
@@ -535,25 +560,38 @@ async function authorizeGoogle(opts = {}) {
|
|
|
535
560
|
//#endregion
|
|
536
561
|
//#region src/google/authFlow.ts
|
|
537
562
|
var createGoogleAuthFlow = (authorize) => {
|
|
538
|
-
let inFlightStart = null;
|
|
539
563
|
let flowRunning = false;
|
|
540
564
|
let lastError = null;
|
|
541
|
-
|
|
565
|
+
let active = null;
|
|
566
|
+
const launch = () => {
|
|
567
|
+
const controller = new AbortController();
|
|
568
|
+
active = controller;
|
|
542
569
|
flowRunning = true;
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
570
|
+
return new Promise((resolve, reject) => {
|
|
571
|
+
authorize({
|
|
572
|
+
onAuthUrl: (url) => resolve({ authUrl: url }),
|
|
573
|
+
signal: controller.signal
|
|
574
|
+
}).then(() => log.info("google", "authorize flow completed")).catch((err) => {
|
|
575
|
+
if (!controller.signal.aborted) {
|
|
576
|
+
lastError = errorMessage(err);
|
|
577
|
+
log.warn("google", "authorize flow failed", { error: lastError });
|
|
578
|
+
}
|
|
579
|
+
reject(err instanceof Error ? err : new Error(String(err)));
|
|
580
|
+
}).finally(() => {
|
|
581
|
+
if (active === controller) {
|
|
582
|
+
flowRunning = false;
|
|
583
|
+
active = null;
|
|
584
|
+
}
|
|
585
|
+
});
|
|
550
586
|
});
|
|
551
|
-
}
|
|
587
|
+
};
|
|
588
|
+
const cancel = () => {
|
|
589
|
+
active?.abort();
|
|
590
|
+
};
|
|
552
591
|
const start = () => {
|
|
553
|
-
|
|
592
|
+
cancel();
|
|
554
593
|
lastError = null;
|
|
555
|
-
|
|
556
|
-
return inFlightStart;
|
|
594
|
+
return launch();
|
|
557
595
|
};
|
|
558
596
|
const status = () => ({
|
|
559
597
|
pending: flowRunning,
|
|
@@ -561,6 +599,7 @@ var createGoogleAuthFlow = (authorize) => {
|
|
|
561
599
|
});
|
|
562
600
|
return {
|
|
563
601
|
start,
|
|
602
|
+
cancel,
|
|
564
603
|
status
|
|
565
604
|
};
|
|
566
605
|
};
|
|
@@ -863,6 +902,7 @@ async function deleteDriveFile(accessToken, input) {
|
|
|
863
902
|
}
|
|
864
903
|
//#endregion
|
|
865
904
|
exports.DEFAULT_LIST_MAX_RESULTS = DEFAULT_LIST_MAX_RESULTS;
|
|
905
|
+
exports.GOOGLE_AUTH_CANCELLED = GOOGLE_AUTH_CANCELLED;
|
|
866
906
|
exports.GOOGLE_CALENDARLIST_SCOPE = GOOGLE_CALENDARLIST_SCOPE;
|
|
867
907
|
exports.GOOGLE_CALENDAR_SCOPE = GOOGLE_CALENDAR_SCOPE;
|
|
868
908
|
exports.GOOGLE_DRIVE_FILE_SCOPE = GOOGLE_DRIVE_FILE_SCOPE;
|
|
@@ -879,6 +919,7 @@ exports.buildMultipartBody = buildMultipartBody;
|
|
|
879
919
|
exports.calendarApiError = calendarApiError;
|
|
880
920
|
exports.clientSecretPresence = clientSecretPresence;
|
|
881
921
|
exports.collectCalendarPages = collectCalendarPages;
|
|
922
|
+
exports.commitLinkedTokens = commitLinkedTokens;
|
|
882
923
|
exports.completeTask = completeTask;
|
|
883
924
|
exports.configureGoogleHost = configureGoogleHost;
|
|
884
925
|
exports.createCalendarEvent = createCalendarEvent;
|