@4fu/arbor-tools 0.1.0 → 2026.1106.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 +8 -5
- package/catalog.d.ts +71 -11
- package/catalog.js +177 -31
- package/child-env.d.ts +24 -0
- package/child-env.js +32 -0
- package/code-exec.d.ts +23 -7
- package/code-exec.js +43 -15
- package/groups/core.d.ts +1 -1
- package/groups/core.js +21 -12
- package/groups/external.d.ts +25 -0
- package/groups/external.js +45 -0
- package/groups/files.d.ts +8 -0
- package/groups/files.js +45 -24
- package/groups/notes.d.ts +6 -0
- package/groups/notes.js +52 -25
- package/host.d.ts +0 -2
- package/index.d.ts +4 -1
- package/index.js +3 -0
- package/modules/modules.d.ts +8 -1
- package/modules/modules.js +69 -13
- package/package.json +8 -4
package/modules/modules.js
CHANGED
|
@@ -12,6 +12,10 @@ import { isAbsolute, join, normalize, resolve } from "node:path";
|
|
|
12
12
|
import { formatTime, textOf } from "@4fu/arbor-prompt";
|
|
13
13
|
import { moduleSpec, refused } from "../host.js";
|
|
14
14
|
import { envCommand } from "../env-stage.js";
|
|
15
|
+
/** How many returned items carry a 相关 line of their own. */
|
|
16
|
+
const RELATED_ITEMS = 3;
|
|
17
|
+
/** How many neighbours one 相关 line names before it says there are more. */
|
|
18
|
+
const RELATED_LIMIT = 3;
|
|
15
19
|
/** `journal`: search, show, around, trace, links. */
|
|
16
20
|
export class JournalModuleGroup {
|
|
17
21
|
id = "modules.journal";
|
|
@@ -41,12 +45,12 @@ export class JournalModuleGroup {
|
|
|
41
45
|
const page = await journal.search(stringArg(args, "query"), {
|
|
42
46
|
...(numberArg(args, "limit") === undefined ? {} : { limit: numberArg(args, "limit") }),
|
|
43
47
|
});
|
|
44
|
-
return this.answer(request, page.items.map((hit) => `${hit.ref} ${hit.kind} ${hit.summary}`), page);
|
|
48
|
+
return this.answer(request, page.items.map((hit) => ({ ref: hit.ref, line: `${hit.ref} ${hit.kind} ${hit.summary}` })), page);
|
|
45
49
|
}
|
|
46
50
|
case "journal.show": {
|
|
47
51
|
const refs = eventRefsArg(args, "ref");
|
|
48
52
|
const events = await journal.getMany(refs);
|
|
49
|
-
return this.answer(request, events.map((event) => `${event.ref} ${event.kind} ${bodyOf(event)}`), {
|
|
53
|
+
return this.answer(request, events.map((event) => ({ ref: event.ref, line: `${event.ref} ${event.kind} ${bodyOf(event)}` })), {
|
|
50
54
|
items: events,
|
|
51
55
|
total: events.length,
|
|
52
56
|
limit: events.length,
|
|
@@ -58,7 +62,7 @@ export class JournalModuleGroup {
|
|
|
58
62
|
...(numberArg(args, "before") === undefined ? {} : { before: numberArg(args, "before") }),
|
|
59
63
|
...(numberArg(args, "after") === undefined ? {} : { after: numberArg(args, "after") }),
|
|
60
64
|
});
|
|
61
|
-
return this.answer(request, events.map((event) => `${event.ref} ${event.kind} ${bodyOf(event)}`), {
|
|
65
|
+
return this.answer(request, events.map((event) => ({ ref: event.ref, line: `${event.ref} ${event.kind} ${bodyOf(event)}` })), {
|
|
62
66
|
items: events,
|
|
63
67
|
total: events.length,
|
|
64
68
|
limit: events.length,
|
|
@@ -67,7 +71,7 @@ export class JournalModuleGroup {
|
|
|
67
71
|
}
|
|
68
72
|
case "journal.trace": {
|
|
69
73
|
const node = await journal.trace(refArg(args, "ref"));
|
|
70
|
-
return this.answer(request, [traceText(node, 0)], {
|
|
74
|
+
return this.answer(request, [{ ref: node.ref, line: traceText(node, 0) }], {
|
|
71
75
|
items: [node.ref],
|
|
72
76
|
total: 1,
|
|
73
77
|
limit: 1,
|
|
@@ -78,21 +82,52 @@ export class JournalModuleGroup {
|
|
|
78
82
|
const page = await journal.links(refArg(args, "ref"), {
|
|
79
83
|
...(numberArg(args, "offset") === undefined ? {} : { offset: numberArg(args, "offset") }),
|
|
80
84
|
});
|
|
81
|
-
|
|
85
|
+
// The items are the neighbours already, so this one answer adds no
|
|
86
|
+
// related line of its own.
|
|
87
|
+
return this.answer(request, page.items.map((item) => ({ ref: item.ref, line: `${item.ref} ${item.kind} ${item.summary}` })), page, false);
|
|
82
88
|
}
|
|
83
89
|
default:
|
|
84
90
|
return this.notOwned(request);
|
|
85
91
|
}
|
|
86
92
|
}
|
|
87
|
-
|
|
93
|
+
/**
|
|
94
|
+
* One answer: the items, then one 相关 line per returned item for the first
|
|
95
|
+
* three of them, then the total and the call that pages the rest
|
|
96
|
+
* (docs/prompting.md#information-density).
|
|
97
|
+
*/
|
|
98
|
+
async answer(request, items, page, related = true) {
|
|
88
99
|
const table = this.services.table;
|
|
100
|
+
const lines = items.map((item) => item.line);
|
|
89
101
|
const body = lines.length === 0 ? textOf(table, "result.search.empty") : lines.join("\n");
|
|
90
102
|
return {
|
|
91
103
|
callId: request.callId,
|
|
92
104
|
ok: true,
|
|
93
|
-
content:
|
|
105
|
+
content: [
|
|
106
|
+
body,
|
|
107
|
+
...(related ? await this.related(items) : []),
|
|
108
|
+
textOf(table, "result.search.total", { total: page.total }),
|
|
109
|
+
page.nextCall,
|
|
110
|
+
].join("\n"),
|
|
94
111
|
};
|
|
95
112
|
}
|
|
113
|
+
/** One 相关 line per item, for the first three: no line without neighbours. */
|
|
114
|
+
async related(items) {
|
|
115
|
+
const table = this.services.table;
|
|
116
|
+
const lines = [];
|
|
117
|
+
for (const item of items.slice(0, RELATED_ITEMS)) {
|
|
118
|
+
const page = await this.services.journal.links(item.ref, { limit: RELATED_LIMIT });
|
|
119
|
+
if (page.items.length === 0)
|
|
120
|
+
continue;
|
|
121
|
+
const more = page.total > page.items.length
|
|
122
|
+
? textOf(table, "result.journal.related.more", { total: page.total, offset: page.items.length })
|
|
123
|
+
: "";
|
|
124
|
+
lines.push(textOf(table, "result.journal.related", {
|
|
125
|
+
refs: page.items.map((one) => one.ref).join("、"),
|
|
126
|
+
more,
|
|
127
|
+
}));
|
|
128
|
+
}
|
|
129
|
+
return lines;
|
|
130
|
+
}
|
|
96
131
|
notOwned(request) {
|
|
97
132
|
return {
|
|
98
133
|
callId: request.callId,
|
|
@@ -696,14 +731,24 @@ export class ScheduleModuleGroup {
|
|
|
696
731
|
content: textOf(table, "result.schedule.updated", { ref }),
|
|
697
732
|
};
|
|
698
733
|
}
|
|
699
|
-
/** One repeat rule as one line: only once, a period, or a
|
|
734
|
+
/** One repeat rule as one line: only once, a period, a daily or a weekly time. */
|
|
700
735
|
repeatText(repeat) {
|
|
701
736
|
const table = this.services.table;
|
|
702
737
|
if (repeat === undefined)
|
|
703
738
|
return textOf(table, "result.schedule.once");
|
|
704
|
-
|
|
739
|
+
const base = "everyMs" in repeat
|
|
705
740
|
? textOf(table, "result.schedule.every_ms", { ms: repeat.everyMs })
|
|
706
|
-
:
|
|
741
|
+
: "weekdays" in repeat
|
|
742
|
+
? textOf(table, "result.schedule.weekly", {
|
|
743
|
+
weekdays: [...repeat.weekdays].sort().join("、"),
|
|
744
|
+
time: repeat.at,
|
|
745
|
+
})
|
|
746
|
+
: textOf(table, "result.schedule.daily", { time: repeat.dailyAt });
|
|
747
|
+
const bounds = [
|
|
748
|
+
...(repeat.times === undefined ? [] : [textOf(table, "result.schedule.times", { count: repeat.times })]),
|
|
749
|
+
...(repeat.until === undefined ? [] : [textOf(table, "result.schedule.until", { time: formatTime(repeat.until) })]),
|
|
750
|
+
];
|
|
751
|
+
return `${base}${bounds.join("")}`;
|
|
707
752
|
}
|
|
708
753
|
/** One argument the script did not name in a shape this module can read. */
|
|
709
754
|
badInput(field) {
|
|
@@ -974,7 +1019,9 @@ function taskRefArg(args, name) {
|
|
|
974
1019
|
}
|
|
975
1020
|
/**
|
|
976
1021
|
* One repeat rule, `invalid` when the argument is not one this module can read:
|
|
977
|
-
* a period in milliseconds,
|
|
1022
|
+
* a period in milliseconds, a clock time a firing repeats at daily, or days of
|
|
1023
|
+
* the week with the clock time it fires at on them. `times` and `until` bound
|
|
1024
|
+
* any of the three.
|
|
978
1025
|
*/
|
|
979
1026
|
function repeatArg(args) {
|
|
980
1027
|
const value = args.repeat;
|
|
@@ -983,11 +1030,20 @@ function repeatArg(args) {
|
|
|
983
1030
|
if (typeof value !== "object" || value === null)
|
|
984
1031
|
return "invalid";
|
|
985
1032
|
const repeat = value;
|
|
1033
|
+
const times = typeof repeat.times === "number" && Number.isFinite(repeat.times) && repeat.times >= 0 ? Math.floor(repeat.times) : undefined;
|
|
1034
|
+
const until = typeof repeat.until === "number" && Number.isFinite(repeat.until) ? Math.floor(repeat.until) : undefined;
|
|
1035
|
+
const bounds = { ...(times === undefined ? {} : { times }), ...(until === undefined ? {} : { until }) };
|
|
986
1036
|
if (typeof repeat.everyMs === "number" && Number.isFinite(repeat.everyMs) && repeat.everyMs > 0) {
|
|
987
|
-
return { everyMs: repeat.everyMs };
|
|
1037
|
+
return { everyMs: repeat.everyMs, ...bounds };
|
|
988
1038
|
}
|
|
989
1039
|
if (typeof repeat.dailyAt === "string" && /^\d{1,2}:\d{2}$/u.test(repeat.dailyAt.trim())) {
|
|
990
|
-
return { dailyAt: repeat.dailyAt.trim() };
|
|
1040
|
+
return { dailyAt: repeat.dailyAt.trim(), ...bounds };
|
|
1041
|
+
}
|
|
1042
|
+
if (Array.isArray(repeat.weekdays) && typeof repeat.at === "string" && /^\d{1,2}:\d{2}$/u.test(repeat.at.trim())) {
|
|
1043
|
+
const weekdays = repeat.weekdays.filter((day) => typeof day === "number" && Number.isInteger(day) && day >= 0 && day <= 6);
|
|
1044
|
+
if (weekdays.length === 0)
|
|
1045
|
+
return "invalid";
|
|
1046
|
+
return { weekdays, at: repeat.at.trim(), ...bounds };
|
|
991
1047
|
}
|
|
992
1048
|
return "invalid";
|
|
993
1049
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@4fu/arbor-tools",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2026.1106.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "The entry points: direct tools, code mode modules and the one tool catalog that routes both through the service layer.",
|
|
6
6
|
"exports": {
|
|
@@ -16,6 +16,8 @@
|
|
|
16
16
|
"bound.js",
|
|
17
17
|
"catalog.d.ts",
|
|
18
18
|
"catalog.js",
|
|
19
|
+
"child-env.d.ts",
|
|
20
|
+
"child-env.js",
|
|
19
21
|
"code-exec.d.ts",
|
|
20
22
|
"code-exec.js",
|
|
21
23
|
"env-stage.d.ts",
|
|
@@ -24,6 +26,8 @@
|
|
|
24
26
|
"groups/core.js",
|
|
25
27
|
"groups/env.d.ts",
|
|
26
28
|
"groups/env.js",
|
|
29
|
+
"groups/external.d.ts",
|
|
30
|
+
"groups/external.js",
|
|
27
31
|
"groups/files.d.ts",
|
|
28
32
|
"groups/files.js",
|
|
29
33
|
"groups/notes.d.ts",
|
|
@@ -50,8 +54,8 @@
|
|
|
50
54
|
"access": "public"
|
|
51
55
|
},
|
|
52
56
|
"dependencies": {
|
|
53
|
-
"@4fu/arbor-errors": "
|
|
54
|
-
"@4fu/arbor-interfaces": "
|
|
55
|
-
"@4fu/arbor-prompt": "
|
|
57
|
+
"@4fu/arbor-errors": "2026.1106.1",
|
|
58
|
+
"@4fu/arbor-interfaces": "2026.1106.1",
|
|
59
|
+
"@4fu/arbor-prompt": "2026.1106.1"
|
|
56
60
|
}
|
|
57
61
|
}
|