@mulmoclaude/core 0.8.1 → 0.8.2
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/collection/core/dynamicIcon.d.ts +24 -0
- package/dist/collection/core/schema.d.ts +55 -0
- package/dist/collection/core/where.d.ts +32 -0
- package/dist/collection/index.cjs +5 -1
- package/dist/collection/index.d.ts +2 -0
- package/dist/collection/index.js +2 -2
- package/dist/collection/registry/server/index.cjs +1 -1
- package/dist/collection/registry/server/index.js +1 -1
- package/dist/collection/server/discovery.d.ts +51 -0
- package/dist/collection/server/dynamicIcon.d.ts +10 -0
- package/dist/collection/server/index.cjs +2 -1
- package/dist/collection/server/index.d.ts +1 -0
- package/dist/collection/server/index.js +2 -2
- package/dist/collection-watchers/index.cjs +1 -1
- package/dist/collection-watchers/index.js +1 -1
- package/dist/{deriveAll-Cb9rWjan.cjs → deriveAll-BQ_p5HSB.cjs} +149 -1
- package/dist/deriveAll-BQ_p5HSB.cjs.map +1 -0
- package/dist/{deriveAll-D3wFH4Tw.js → deriveAll-CMFXDQ_G.js} +126 -2
- package/dist/deriveAll-CMFXDQ_G.js.map +1 -0
- package/dist/feeds/index.cjs +2 -2
- package/dist/feeds/index.js +2 -2
- package/dist/feeds/server/index.cjs +3 -3
- package/dist/feeds/server/index.js +3 -3
- package/dist/{ingestTypes-DhJ63Ogd.cjs → ingestTypes-C7EheYZX.cjs} +2 -2
- package/dist/{ingestTypes-DhJ63Ogd.cjs.map → ingestTypes-C7EheYZX.cjs.map} +1 -1
- package/dist/{ingestTypes-BtMZogMX.js → ingestTypes-CmJeOUJc.js} +2 -2
- package/dist/{ingestTypes-BtMZogMX.js.map → ingestTypes-CmJeOUJc.js.map} +1 -1
- package/dist/{server-BDxrLT41.js → server-DKXXFTbw.js} +96 -4
- package/dist/server-DKXXFTbw.js.map +1 -0
- package/dist/{server-U2d7Fb1h.cjs → server-G6GtOdaW.cjs} +101 -3
- package/dist/server-G6GtOdaW.cjs.map +1 -0
- package/package.json +2 -2
- package/dist/deriveAll-Cb9rWjan.cjs.map +0 -1
- package/dist/deriveAll-D3wFH4Tw.js.map +0 -1
- package/dist/server-BDxrLT41.js.map +0 -1
- package/dist/server-U2d7Fb1h.cjs.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ingestTypes-
|
|
1
|
+
{"version":3,"file":"ingestTypes-CmJeOUJc.js","names":[],"sources":["../src/feeds/ingestTypes.ts"],"sourcesContent":["// Declarative retrieval config for the \"Feeds\" mechanism. A Feed is a\n// CollectionSchema plus this `ingest` block, registered as data (NOT as\n// a skill) under `<workspace>/feeds/<slug>/schema.json`. The host's\n// retrieval engine reads it to periodically refill the collection's\n// records via the shared collections io layer.\n//\n// The ingest vocab (INGEST_KINDS / FEED_SCHEDULES + their literal-union types)\n// lives in the sibling `../collection` subpath alongside the schema contract, so\n// the package's schema validator can enforce it. Re-exported here so the feeds\n// engine's existing importers resolve them unchanged.\nimport { type CollectionIngest, INGEST_KINDS, FEED_SCHEDULES, type IngestKind, type FeedSchedule } from \"../collection/index.js\";\n//\n// Two flavours: the declarative kinds (`rss`/`atom`/`http-json`) fetch-and-map,\n// and `agent` dispatches a hidden worker. The `code` kind (LLM-generated\n// deterministic transform) is still reserved for a future retriever.\n\n// The agent ingest kind. Defined HERE (not imported from `../collection`) on\n// purpose: the engine only needs the literal to branch, and re-importing it as a\n// VALUE keeps this module free of a value dependency on the collection vocab.\n// Core owns its own copy for the schema validator; this matches the same literal.\nexport const AGENT_INGEST_KIND = \"agent\" as const;\nexport type AgentIngestKind = typeof AGENT_INGEST_KIND;\n\nexport { INGEST_KINDS, FEED_SCHEDULES, type IngestKind, type FeedSchedule };\n\nconst FEED_SCHEDULE_SET: ReadonlySet<string> = new Set(FEED_SCHEDULES);\n\nexport function isFeedSchedule(value: unknown): value is FeedSchedule {\n return typeof value === \"string\" && FEED_SCHEDULE_SET.has(value);\n}\n\n/** Default cap on stored records per feed when `ingest.maxItems` is\n * omitted. Keeps high-volume feeds (news / podcasts) bounded. */\nexport const DEFAULT_FEED_MAX_ITEMS = 100;\n\n/** Declarative field map: target collection field name → source path\n * into the raw item (dot/bracket path, e.g. `\"title\"` or\n * `\"data.name\"`). */\nexport type IngestFieldMap = Record<string, string>;\n\n/** Declarative retrieval (`rss`/`atom`/`http-json`): the host fetches `url`\n * and projects each item through `map`. The canonical schema (in\n * `../collection`) only promises the minimal `CollectionIngest`; this\n * feeds-only subtype narrows those + adds the retrieval fields the engine\n * needs. */\nexport interface DeclarativeIngestSpec extends CollectionIngest {\n /** Which declarative retriever handles this feed. */\n kind: IngestKind;\n /** Endpoint to fetch (http/https). */\n url: string;\n /** Refresh cadence. */\n schedule: FeedSchedule;\n /** `http-json` only: dot/bracket path to the array of items in the\n * response (e.g. `\"hourly[]\"` or `\"data.results[]\"`). Ignored for\n * `rss`/`atom`, which yield items natively. */\n itemsAt?: string;\n /** target field → source path. Projects each raw item into a record\n * whose keys match the schema's `fields`. */\n map: IngestFieldMap;\n /** Optional source path used to derive the primaryKey value when the\n * mapped record's primaryKey is empty (e.g. `\"feedId\"`). Falls back\n * to a content hash of the record. */\n idFrom?: string;\n /** Cap on stored records. After each fetch the feed keeps only the\n * newest `maxItems` (ordered by the schema's first `date` field) and\n * deletes the rest. Defaults to {@link DEFAULT_FEED_MAX_ITEMS} when\n * omitted; `0` disables the cap (keep everything). Pruning is skipped\n * when the schema has no `date` field to order by. */\n maxItems?: number;\n}\n\n/** Agent-performed retrieval (`kind: \"agent\"`). No `url`/`map`: the host seeds\n * a hidden background worker (origin `system`) in `role` with `template` + a\n * summary of every record, and the worker edits the records itself via the\n * collections io layer. Valid on any collection (primarily skill-backed). */\nexport interface AgentIngestSpec extends CollectionIngest {\n kind: AgentIngestKind;\n /** Refresh cadence (same vocabulary as declarative feeds). */\n schedule: FeedSchedule;\n /** Role id the scheduled hidden worker runs in. */\n role: string;\n /** Skill-relative template path (under `templates/`) seeding the worker. */\n template: string;\n}\n\n/** The `ingest` block carried on a `CollectionSchema`, discriminated on `kind`. */\nexport type IngestSpec = DeclarativeIngestSpec | AgentIngestSpec;\n"],"mappings":";;;AAoBA,IAAa,oBAAoB;AAKjC,IAAM,oBAAyC,IAAI,IAAI,cAAc;AAErE,SAAgB,eAAe,OAAuC;CACpE,OAAO,OAAO,UAAU,YAAY,kBAAkB,IAAI,KAAK;AACjE;;;AAIA,IAAa,yBAAyB"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as
|
|
1
|
+
import { a as resolveIcon, c as AGENT_INGEST_KIND, d as embedTargetId, f as isFieldDrivenEvery, i as firstDateField, l as FEED_SCHEDULES, o as selectDynamicRecord, t as deriveAll, u as INGEST_KINDS } from "./deriveAll-CMFXDQ_G.js";
|
|
2
2
|
import { isSafeActionTemplatePath, isSafeCustomViewI18nPath, isSafeCustomViewPath } from "./collection/paths.js";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { promises, realpathSync } from "node:fs";
|
|
@@ -970,6 +970,51 @@ var AgentIngestZ = z.object({
|
|
|
970
970
|
template: z.string().trim().min(1).refine(isSafeActionTemplatePath, "must be a safe path under `templates/` (e.g. `templates/refresh.md`; no `..`, no leading `/`, no backslash)")
|
|
971
971
|
});
|
|
972
972
|
var IngestSchemaZ = z.discriminatedUnion("kind", [DeclarativeIngestZ, AgentIngestZ]);
|
|
973
|
+
var ValueRefZ = z.object({
|
|
974
|
+
record: z.string().trim().min(1).optional(),
|
|
975
|
+
field: z.string().trim().min(1)
|
|
976
|
+
});
|
|
977
|
+
var WhereCondZ = z.object({
|
|
978
|
+
field: z.string().trim().min(1),
|
|
979
|
+
op: z.enum([
|
|
980
|
+
"eq",
|
|
981
|
+
"ne",
|
|
982
|
+
"in",
|
|
983
|
+
"gt",
|
|
984
|
+
"gte",
|
|
985
|
+
"lt",
|
|
986
|
+
"lte",
|
|
987
|
+
"contains"
|
|
988
|
+
]),
|
|
989
|
+
value: z.union([z.string(), z.array(z.string())]).optional(),
|
|
990
|
+
valueFrom: ValueRefZ.optional()
|
|
991
|
+
}).refine((cond) => cond.value !== void 0 !== (cond.valueFrom !== void 0), {
|
|
992
|
+
message: "a where condition must declare exactly one of `value` (a literal) or `valueFrom` (a reference to another record's field), never both or neither",
|
|
993
|
+
path: ["value"]
|
|
994
|
+
}).refine((cond) => cond.value === void 0 || cond.op === "in" === Array.isArray(cond.value), {
|
|
995
|
+
message: "`in` requires an array `value` (the allowed set); every other op requires a single string `value`",
|
|
996
|
+
path: ["value"]
|
|
997
|
+
});
|
|
998
|
+
var WhereZ = z.array(WhereCondZ);
|
|
999
|
+
var DynamicIconSourceZ = z.object({
|
|
1000
|
+
collection: z.string().trim().min(1),
|
|
1001
|
+
from: z.enum([
|
|
1002
|
+
"latest",
|
|
1003
|
+
"first",
|
|
1004
|
+
"when"
|
|
1005
|
+
]).optional(),
|
|
1006
|
+
orderBy: z.string().trim().min(1).optional(),
|
|
1007
|
+
where: WhereZ.optional()
|
|
1008
|
+
});
|
|
1009
|
+
var DynamicIconRuleZ = z.object({
|
|
1010
|
+
where: WhereZ,
|
|
1011
|
+
icon: z.string().trim().min(1)
|
|
1012
|
+
});
|
|
1013
|
+
var DynamicIconSpecZ = z.object({
|
|
1014
|
+
source: DynamicIconSourceZ,
|
|
1015
|
+
rules: z.array(DynamicIconRuleZ),
|
|
1016
|
+
fallback: z.string().trim().min(1).optional()
|
|
1017
|
+
});
|
|
973
1018
|
var CollectionSchemaZ = z.object({
|
|
974
1019
|
title: z.string().min(1),
|
|
975
1020
|
icon: z.string().min(1),
|
|
@@ -991,7 +1036,8 @@ var CollectionSchemaZ = z.object({
|
|
|
991
1036
|
kanbanField: z.string().trim().min(1).optional(),
|
|
992
1037
|
views: z.array(CustomViewSchema).optional(),
|
|
993
1038
|
notifyWhen: WhenSchema.optional(),
|
|
994
|
-
ingest: IngestSchemaZ.optional()
|
|
1039
|
+
ingest: IngestSchemaZ.optional(),
|
|
1040
|
+
dynamicIcon: DynamicIconSpecZ.optional()
|
|
995
1041
|
}).refine((schema) => schema.singleton === void 0 || safeRecordId(schema.singleton) !== null, {
|
|
996
1042
|
message: "schema `singleton` must be a valid item id (alphanumeric / hyphen / underscore / interior dot, no `..` or path separators)",
|
|
997
1043
|
path: ["singleton"]
|
|
@@ -1347,6 +1393,52 @@ async function enrichItems(collection, items, opts = {}) {
|
|
|
1347
1393
|
return items.map((item) => projectComputed(schema, deriveAll(schema, item, refRecords), linked));
|
|
1348
1394
|
}
|
|
1349
1395
|
//#endregion
|
|
1396
|
+
//#region src/collection/server/dynamicIcon.ts
|
|
1397
|
+
/** Index `items` by their `primaryKey` value — the `recordsById` map a
|
|
1398
|
+
* `valueFrom` reference (e.g. `_config.defaultCity`) resolves against.
|
|
1399
|
+
* Items whose primary key isn't a string (shouldn't happen for a valid
|
|
1400
|
+
* schema, but records are untyped storage) are skipped rather than
|
|
1401
|
+
* coerced, so a broken key never silently shadows a real one. */
|
|
1402
|
+
function buildRecordsById(items, primaryKey) {
|
|
1403
|
+
const entries = items.filter((item) => typeof item[primaryKey] === "string").map((item) => [String(item[primaryKey]), item]);
|
|
1404
|
+
return Object.fromEntries(entries);
|
|
1405
|
+
}
|
|
1406
|
+
/** Order records by their `primaryKey` so record selection is deterministic:
|
|
1407
|
+
* `listItems` returns filesystem `readdir` order (arbitrary across machines),
|
|
1408
|
+
* which would let `from: "first"`, the no-`orderBy` `latest`, and `orderBy`
|
|
1409
|
+
* ties pick a different record — and thus a different icon — between
|
|
1410
|
+
* reconciles. A stable id sort pins one answer. */
|
|
1411
|
+
function sortByPrimaryKey(items, primaryKey) {
|
|
1412
|
+
return [...items].sort((left, right) => String(left[primaryKey] ?? "").localeCompare(String(right[primaryKey] ?? "")));
|
|
1413
|
+
}
|
|
1414
|
+
/** Compute the effective launcher icon for `collection`: its static
|
|
1415
|
+
* `schema.icon` when it declares no `dynamicIcon`, else the icon
|
|
1416
|
+
* resolved from `dynamicIcon.source`'s RAW stored records (no
|
|
1417
|
+
* derive/enrich — the icon rules match against stored values) via the
|
|
1418
|
+
* pure resolver. Fails soft on any read/discovery error (missing source
|
|
1419
|
+
* collection, filesystem error): falls back to `dynamicIcon.fallback ??
|
|
1420
|
+
* schema.icon` rather than surfacing to the collections list. */
|
|
1421
|
+
async function computeCollectionIcon(collection, opts = {}) {
|
|
1422
|
+
const { schema } = collection;
|
|
1423
|
+
const spec = schema.dynamicIcon;
|
|
1424
|
+
if (!spec) return schema.icon;
|
|
1425
|
+
try {
|
|
1426
|
+
const source = await loadCollection(spec.source.collection, opts);
|
|
1427
|
+
if (!source) return spec.fallback ?? schema.icon;
|
|
1428
|
+
const ordered = sortByPrimaryKey(await listItems(source.dataDir, { workspaceRoot: opts.workspaceRoot }), source.schema.primaryKey);
|
|
1429
|
+
const orderBy = spec.source.orderBy ?? firstDateField(source.schema);
|
|
1430
|
+
const recordsById = buildRecordsById(ordered, source.schema.primaryKey);
|
|
1431
|
+
return resolveIcon(selectDynamicRecord(ordered, spec.source, orderBy, recordsById), spec, schema.icon, recordsById);
|
|
1432
|
+
} catch (err) {
|
|
1433
|
+
log.warn("collections", "dynamic icon compute failed, falling back", {
|
|
1434
|
+
slug: collection.slug,
|
|
1435
|
+
source: spec.source.collection,
|
|
1436
|
+
error: String(err)
|
|
1437
|
+
});
|
|
1438
|
+
return spec.fallback ?? schema.icon;
|
|
1439
|
+
}
|
|
1440
|
+
}
|
|
1441
|
+
//#endregion
|
|
1350
1442
|
//#region src/collection/server/util.ts
|
|
1351
1443
|
/** Human-readable message from an unknown thrown value. */
|
|
1352
1444
|
function errorMessage(err) {
|
|
@@ -1823,6 +1915,6 @@ async function deleteCustomView(collection, viewId, opts = {}) {
|
|
|
1823
1915
|
};
|
|
1824
1916
|
}
|
|
1825
1917
|
//#endregion
|
|
1826
|
-
export {
|
|
1918
|
+
export { listItems as A, isContainedInRoot as B, COMPUTED_TYPES as C, buildCollectionActionSeedPrompt as D, buildActionSeedPrompt as E, readSkillTemplate as F, safeRecordId as G, itemFilePath as H, resolveCreateItemId as I, configureCollectionHost as J, safeSlugName as K, writeItem as L, readCustomViewHtml as M, readCustomViewI18n as N, deleteItem as O, readItem as P, setCollectionChangePublisher as Q, writeFileAtomic as R, toSummary as S, validateRecordObject as T, resolveDataDir as U, isContainedInWorkspace as V, resolveTemplatePath as W, log as X, getWorkspaceRoot as Y, publishCollectionChange as Z, CollectionSchemaZ as _, computeSuccessor as a, loadCollection as b, isTriggerDue as c, resolveEvery as d, successorId as f, enrichItems as g, computeCollectionIcon as h, advanceTriggerDate as i, promptPathsFor as j, generateItemId as k, maybeSpawnSuccessor as l, errorMessage as m, deleteCollection as n, daysInMonth as o, ONE_SECOND_MS as p, collectionsRegistriesConfigPath as q, deleteCollectionRefusalMessage as r, formatCivil as s, deleteCustomView as t, parseCivil as u, acceptParsedSchema as v, validateCollectionRecords as w, toDetail as x, discoverCollections as y, SCHEMA_FILE as z };
|
|
1827
1919
|
|
|
1828
|
-
//# sourceMappingURL=server-
|
|
1920
|
+
//# sourceMappingURL=server-DKXXFTbw.js.map
|