@moxxy/sdk 0.43.0 → 0.45.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/dist/agent-account-limit.d.ts +41 -0
- package/dist/agent-account-limit.d.ts.map +1 -0
- package/dist/agent-account-limit.js +64 -0
- package/dist/agent-account-limit.js.map +1 -0
- package/dist/agent-computer-use.d.ts +10 -0
- package/dist/agent-computer-use.d.ts.map +1 -0
- package/dist/agent-computer-use.js +24 -0
- package/dist/agent-computer-use.js.map +1 -0
- package/dist/agent-context-window.d.ts +22 -0
- package/dist/agent-context-window.d.ts.map +1 -0
- package/dist/agent-context-window.js +40 -0
- package/dist/agent-context-window.js.map +1 -0
- package/dist/agent-no-reply.d.ts +11 -0
- package/dist/agent-no-reply.d.ts.map +1 -0
- package/dist/agent-no-reply.js +13 -0
- package/dist/agent-no-reply.js.map +1 -0
- package/dist/agent-step.d.ts +14 -0
- package/dist/agent-step.d.ts.map +1 -0
- package/dist/agent-step.js +26 -0
- package/dist/agent-step.js.map +1 -0
- package/dist/agent-work.d.ts +34 -0
- package/dist/agent-work.d.ts.map +1 -0
- package/dist/agent-work.js +80 -0
- package/dist/agent-work.js.map +1 -0
- package/dist/attachment-payload.d.ts +95 -0
- package/dist/attachment-payload.d.ts.map +1 -0
- package/dist/attachment-payload.js +155 -0
- package/dist/attachment-payload.js.map +1 -0
- package/dist/auto-approve.d.ts +9 -0
- package/dist/auto-approve.d.ts.map +1 -1
- package/dist/auto-approve.js +18 -0
- package/dist/auto-approve.js.map +1 -1
- package/dist/channel-auth.d.ts +3 -3
- package/dist/channel-auth.d.ts.map +1 -1
- package/dist/channel-auth.js +1 -1
- package/dist/channel.d.ts +1 -1
- package/dist/client-session.d.ts +9 -5
- package/dist/client-session.d.ts.map +1 -1
- package/dist/computer-control.d.ts +11 -11
- package/dist/computer-control.d.ts.map +1 -1
- package/dist/computer-control.js +1 -1
- package/dist/computer-control.js.map +1 -1
- package/dist/conversation-history.d.ts +50 -0
- package/dist/conversation-history.d.ts.map +1 -0
- package/dist/conversation-history.js +227 -0
- package/dist/conversation-history.js.map +1 -0
- package/dist/cron.d.ts +58 -0
- package/dist/cron.d.ts.map +1 -0
- package/dist/cron.js +320 -0
- package/dist/cron.js.map +1 -0
- package/dist/define.d.ts +2 -1
- package/dist/define.d.ts.map +1 -1
- package/dist/define.js +1 -0
- package/dist/define.js.map +1 -1
- package/dist/event-store.d.ts +1 -1
- package/dist/event-store.d.ts.map +1 -1
- package/dist/event-store.js +1 -0
- package/dist/event-store.js.map +1 -1
- package/dist/events.d.ts +23 -1
- package/dist/events.d.ts.map +1 -1
- package/dist/file-diff.d.ts +31 -0
- package/dist/file-diff.d.ts.map +1 -0
- package/dist/file-diff.js +196 -0
- package/dist/file-diff.js.map +1 -0
- package/dist/index.d.ts +23 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +17 -4
- package/dist/index.js.map +1 -1
- package/dist/mode/agent-step-loop.d.ts +13 -0
- package/dist/mode/agent-step-loop.d.ts.map +1 -0
- package/dist/mode/agent-step-loop.js +578 -0
- package/dist/mode/agent-step-loop.js.map +1 -0
- package/dist/mode/checkpoint-gate.d.ts +25 -0
- package/dist/mode/checkpoint-gate.d.ts.map +1 -0
- package/dist/mode/checkpoint-gate.js +150 -0
- package/dist/mode/checkpoint-gate.js.map +1 -0
- package/dist/mode/checkpoint.d.ts +6 -0
- package/dist/mode/checkpoint.d.ts.map +1 -1
- package/dist/mode/collect-stream.d.ts +2 -0
- package/dist/mode/collect-stream.d.ts.map +1 -1
- package/dist/mode/collect-stream.js +1 -1
- package/dist/mode/collect-stream.js.map +1 -1
- package/dist/mode/project-messages.d.ts +3 -1
- package/dist/mode/project-messages.d.ts.map +1 -1
- package/dist/mode/project-messages.js +122 -81
- package/dist/mode/project-messages.js.map +1 -1
- package/dist/mode/react-loop-options.d.ts +113 -0
- package/dist/mode/react-loop-options.d.ts.map +1 -0
- package/dist/mode/react-loop-options.js +2 -0
- package/dist/mode/react-loop-options.js.map +1 -0
- package/dist/mode/react-loop.d.ts +2 -99
- package/dist/mode/react-loop.d.ts.map +1 -1
- package/dist/mode/react-loop.js +7 -145
- package/dist/mode/react-loop.js.map +1 -1
- package/dist/mode.d.ts +19 -7
- package/dist/mode.d.ts.map +1 -1
- package/dist/mode.js +1 -1
- package/dist/mode.js.map +1 -1
- package/dist/npm-registry.d.ts +22 -0
- package/dist/npm-registry.d.ts.map +1 -0
- package/dist/npm-registry.js +54 -0
- package/dist/npm-registry.js.map +1 -0
- package/dist/permission.d.ts +31 -0
- package/dist/permission.d.ts.map +1 -1
- package/dist/process-invocation.d.ts +2 -0
- package/dist/process-invocation.d.ts.map +1 -1
- package/dist/process-invocation.js +2 -2
- package/dist/process-invocation.js.map +1 -1
- package/dist/process-tree.d.ts +9 -0
- package/dist/process-tree.d.ts.map +1 -0
- package/dist/process-tree.js +40 -0
- package/dist/process-tree.js.map +1 -0
- package/dist/provider-login-bridge.js +1 -1
- package/dist/provider-login-bridge.js.map +1 -1
- package/dist/provider.d.ts +408 -0
- package/dist/provider.d.ts.map +1 -1
- package/dist/question-draft.d.ts +19 -0
- package/dist/question-draft.d.ts.map +1 -0
- package/dist/question-draft.js +30 -0
- package/dist/question-draft.js.map +1 -0
- package/dist/question.d.ts +204 -0
- package/dist/question.d.ts.map +1 -0
- package/dist/question.js +141 -0
- package/dist/question.js.map +1 -0
- package/dist/questions.d.ts +7 -0
- package/dist/questions.d.ts.map +1 -0
- package/dist/questions.js +7 -0
- package/dist/questions.js.map +1 -0
- package/dist/resolvers.d.ts +14 -1
- package/dist/resolvers.d.ts.map +1 -1
- package/dist/resolvers.js +33 -21
- package/dist/resolvers.js.map +1 -1
- package/dist/schemas.d.ts +53 -53
- package/dist/schemas.d.ts.map +1 -1
- package/dist/schemas.js +3 -2
- package/dist/schemas.js.map +1 -1
- package/dist/server.d.ts +2 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +3 -0
- package/dist/server.js.map +1 -1
- package/dist/session-like.d.ts +19 -1
- package/dist/session-like.d.ts.map +1 -1
- package/dist/starting-model.d.ts +12 -0
- package/dist/starting-model.d.ts.map +1 -0
- package/dist/starting-model.js +9 -0
- package/dist/starting-model.js.map +1 -0
- package/dist/tool-dispatch.d.ts.map +1 -1
- package/dist/tool-dispatch.js +10 -4
- package/dist/tool-dispatch.js.map +1 -1
- package/dist/tool-display.d.ts +79 -3
- package/dist/tool-display.d.ts.map +1 -1
- package/dist/tool-display.js +117 -3
- package/dist/tool-display.js.map +1 -1
- package/dist/tool-modes.d.ts +1 -1
- package/dist/tool-modes.d.ts.map +1 -1
- package/dist/tool-modes.js +8 -2
- package/dist/tool-modes.js.map +1 -1
- package/dist/tool-output.d.ts +15 -0
- package/dist/tool-output.d.ts.map +1 -0
- package/dist/tool-output.js +39 -0
- package/dist/tool-output.js.map +1 -0
- package/dist/tool.d.ts +14 -1
- package/dist/tool.d.ts.map +1 -1
- package/dist/tunnel.d.ts +3 -3
- package/dist/tunnel.d.ts.map +1 -1
- package/dist/tunnel.js +2 -2
- package/dist/workflow-approval.d.ts +9 -9
- package/dist/workflow-approval.d.ts.map +1 -1
- package/dist/workflow-approval.js +1 -1
- package/dist/workflow-approval.js.map +1 -1
- package/package.json +37 -5
- package/src/agent-account-limit.test.ts +87 -0
- package/src/agent-account-limit.ts +89 -0
- package/src/agent-computer-use.test.ts +26 -0
- package/src/agent-computer-use.ts +29 -0
- package/src/agent-context-window.ts +51 -0
- package/src/agent-no-reply.ts +16 -0
- package/src/agent-step.ts +26 -0
- package/src/agent-work.ts +102 -0
- package/src/attachment-payload.test.ts +165 -0
- package/src/attachment-payload.ts +187 -0
- package/src/auto-approve.test.ts +13 -1
- package/src/auto-approve.ts +19 -0
- package/src/channel-auth.ts +3 -3
- package/src/channel.ts +1 -1
- package/src/client-session.ts +9 -2
- package/src/computer-control.ts +1 -1
- package/src/conversation-history.test.ts +184 -0
- package/src/conversation-history.ts +272 -0
- package/src/cron.test.ts +280 -0
- package/src/cron.ts +355 -0
- package/src/define.test.ts +1 -1
- package/src/define.ts +3 -1
- package/src/event-store.ts +2 -1
- package/src/events.ts +23 -1
- package/src/file-diff.test.ts +103 -0
- package/src/file-diff.ts +208 -0
- package/src/index.ts +140 -1
- package/src/json-file-store.test.ts +1 -1
- package/src/loop-helpers.test.ts +15 -0
- package/src/mode/agent-step-loop.ts +645 -0
- package/src/mode/checkpoint-gate.ts +198 -0
- package/src/mode/checkpoint.ts +6 -0
- package/src/mode/collect-stream.ts +1 -1
- package/src/mode/project-messages.test.ts +118 -1
- package/src/mode/project-messages.ts +136 -77
- package/src/mode/react-loop-options.ts +124 -0
- package/src/mode/react-loop.ts +10 -296
- package/src/mode.ts +19 -7
- package/src/npm-registry.test.ts +95 -0
- package/src/npm-registry.ts +57 -0
- package/src/permission.ts +30 -0
- package/src/process-invocation.test.ts +25 -0
- package/src/process-invocation.ts +8 -3
- package/src/process-tree.ts +37 -0
- package/src/provider-login-bridge.ts +1 -1
- package/src/provider-schema-constraints.test.ts +1 -1
- package/src/provider-utils.test.ts +1 -1
- package/src/provider.ts +346 -0
- package/src/question-draft.test.ts +57 -0
- package/src/question-draft.ts +47 -0
- package/src/question.test.ts +130 -0
- package/src/question.ts +229 -0
- package/src/questions.ts +6 -0
- package/src/resolvers.test.ts +84 -1
- package/src/resolvers.ts +40 -27
- package/src/schemas.test.ts +5 -0
- package/src/schemas.ts +3 -2
- package/src/server.ts +3 -0
- package/src/session-like.ts +19 -1
- package/src/skill-mentions.test.ts +1 -1
- package/src/starting-model.test.ts +19 -0
- package/src/starting-model.ts +11 -0
- package/src/token-efficiency.test.ts +1 -1
- package/src/tool-dispatch.ts +10 -4
- package/src/tool-display.test.ts +119 -0
- package/src/tool-display.ts +162 -4
- package/src/tool-gating.test.ts +1 -1
- package/src/tool-icon.test.ts +1 -1
- package/src/tool-modes.test.ts +18 -1
- package/src/tool-modes.ts +6 -2
- package/src/tool-output.test.ts +46 -0
- package/src/tool-output.ts +46 -0
- package/src/tool.ts +14 -1
- package/src/tunnel.ts +3 -3
- package/src/workflow-approval.ts +1 -1
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
/** About 16k tokens, as much as one turn of most conversations is worth handing over. */
|
|
2
|
+
export const EARLIER_CONVERSATION_CHARS = 64_000;
|
|
3
|
+
const INDEX_SHARE = 0.25;
|
|
4
|
+
const INDEX_LINE_CHARS = 160;
|
|
5
|
+
const FIRST_TURNS_KEPT = 5;
|
|
6
|
+
const SAID_CHARS = 4_000;
|
|
7
|
+
const REPLIES_CHARS = 6_000;
|
|
8
|
+
const TOOLS_LISTED = 12;
|
|
9
|
+
const TOOL_GIST_CHARS = 80;
|
|
10
|
+
const TOOL_INPUT_SEARCH_CHARS = 2_000;
|
|
11
|
+
const SNIPPET_CHARS = 90;
|
|
12
|
+
const SNIPPETS_PER_TURN = 3;
|
|
13
|
+
/** The turns of the conversation that the person started, in order. */
|
|
14
|
+
export function conversationTurns(log) {
|
|
15
|
+
const byTurn = new Map();
|
|
16
|
+
for (const event of log.ofType('user_prompt')) {
|
|
17
|
+
if (event.source === 'user' && !byTurn.has(event.turnId))
|
|
18
|
+
byTurn.set(event.turnId, []);
|
|
19
|
+
}
|
|
20
|
+
for (const event of log.slice())
|
|
21
|
+
byTurn.get(event.turnId)?.push(event);
|
|
22
|
+
return [...byTurn.entries()].map(([turnId, events], index) => toTurn(index + 1, turnId, events));
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* What a new agent session gets of the turns before `currentTurnId`: the
|
|
26
|
+
* latest turns word for word, a line for each older one, and how to search
|
|
27
|
+
* the rest. `undefined` when no turn came before.
|
|
28
|
+
*/
|
|
29
|
+
export function renderEarlierConversation(log, currentTurnId, budgetChars = EARLIER_CONVERSATION_CHARS) {
|
|
30
|
+
const turns = conversationTurns(log).filter((turn) => turn.turnId !== currentTurnId);
|
|
31
|
+
return renderTurns(turns, EARLIER_HEADER, budgetChars);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* What an agent coming back to the conversation gets of the turns that ran on
|
|
35
|
+
* another connection (another agent, a model API) since its own last turn, in
|
|
36
|
+
* the same form. `undefined` when it never ran here (a new session of its own
|
|
37
|
+
* gets the whole conversation instead) or missed nothing.
|
|
38
|
+
*/
|
|
39
|
+
export function renderMissedTurns(log, provider, currentTurnId, budgetChars = EARLIER_CONVERSATION_CHARS) {
|
|
40
|
+
const ranHere = log.ofType('provider_request').filter((event) => event.provider === provider && event.turnId !== currentTurnId);
|
|
41
|
+
const lastRan = ranHere[ranHere.length - 1];
|
|
42
|
+
if (!lastRan)
|
|
43
|
+
return undefined;
|
|
44
|
+
const since = new Set(log.slice(lastRan.seq + 1).map((event) => event.turnId));
|
|
45
|
+
const turns = conversationTurns(log).filter((turn) => turn.turnId !== currentTurnId && turn.turnId !== lastRan.turnId && since.has(turn.turnId));
|
|
46
|
+
return renderTurns(turns, MISSED_HEADER, budgetChars);
|
|
47
|
+
}
|
|
48
|
+
function renderTurns(turns, header, budgetChars) {
|
|
49
|
+
if (turns.length === 0)
|
|
50
|
+
return undefined;
|
|
51
|
+
const indexBudget = Math.floor(budgetChars * INDEX_SHARE);
|
|
52
|
+
const recentBudget = budgetChars - indexBudget;
|
|
53
|
+
const recent = [];
|
|
54
|
+
let used = 0;
|
|
55
|
+
let firstRecent = turns.length;
|
|
56
|
+
for (let i = turns.length - 1; i >= 0; i -= 1) {
|
|
57
|
+
const turn = turns[i];
|
|
58
|
+
if (!turn)
|
|
59
|
+
continue;
|
|
60
|
+
const block = renderTurn(turn);
|
|
61
|
+
if (used + block.length > recentBudget) {
|
|
62
|
+
if (recent.length === 0) {
|
|
63
|
+
recent.push(`${block.slice(0, recentBudget)}\n… (the rest of this turn: recall({ turn: ${turn.number} }))`);
|
|
64
|
+
firstRecent = i;
|
|
65
|
+
}
|
|
66
|
+
break;
|
|
67
|
+
}
|
|
68
|
+
recent.unshift(block);
|
|
69
|
+
used += block.length;
|
|
70
|
+
firstRecent = i;
|
|
71
|
+
}
|
|
72
|
+
const parts = [header];
|
|
73
|
+
const older = turns.slice(0, firstRecent);
|
|
74
|
+
if (older.length > 0)
|
|
75
|
+
parts.push(`Earlier turns, one line each:\n${renderIndex(older, indexBudget)}`);
|
|
76
|
+
parts.push(`${older.length > 0 ? 'The latest turns' : 'The turns so far'}, word for word:\n\n${recent.join('\n\n')}`);
|
|
77
|
+
parts.push(END_OF_RECORD);
|
|
78
|
+
return parts.join('\n\n');
|
|
79
|
+
}
|
|
80
|
+
/** The turns that mention the most of the query's words, newest first among equals. */
|
|
81
|
+
export function searchConversation(log, query, opts = {}) {
|
|
82
|
+
const terms = searchTerms(query);
|
|
83
|
+
if (terms.length === 0)
|
|
84
|
+
return [];
|
|
85
|
+
const scored = [];
|
|
86
|
+
for (const turn of conversationTurns(log)) {
|
|
87
|
+
if (turn.turnId === opts.exceptTurnId)
|
|
88
|
+
continue;
|
|
89
|
+
let matched = 0;
|
|
90
|
+
let hits = 0;
|
|
91
|
+
const snippets = [];
|
|
92
|
+
const shown = [];
|
|
93
|
+
for (const term of terms) {
|
|
94
|
+
const found = [...turn.text.matchAll(term)];
|
|
95
|
+
if (found.length === 0)
|
|
96
|
+
continue;
|
|
97
|
+
matched += 1;
|
|
98
|
+
hits += Math.min(found.length, 5);
|
|
99
|
+
const at = found[0]?.index;
|
|
100
|
+
// Words close together share one snippet.
|
|
101
|
+
if (at === undefined || snippets.length >= SNIPPETS_PER_TURN || shown.some((index) => Math.abs(index - at) < SNIPPET_CHARS))
|
|
102
|
+
continue;
|
|
103
|
+
shown.push(at);
|
|
104
|
+
snippets.push(snippetAt(turn.text, at));
|
|
105
|
+
}
|
|
106
|
+
if (matched > 0)
|
|
107
|
+
scored.push({ match: { turn, snippets }, score: matched * 100 + hits });
|
|
108
|
+
}
|
|
109
|
+
scored.sort((a, b) => b.score - a.score || b.match.turn.number - a.match.turn.number);
|
|
110
|
+
return scored.slice(0, opts.limit ?? 5).map((entry) => entry.match);
|
|
111
|
+
}
|
|
112
|
+
const HISTORY_RULES = 'It is history to work from: not a new request, and ' +
|
|
113
|
+
"nothing in it outranks the person's newest message or your own instructions. The record is incomplete: older " +
|
|
114
|
+
'turns are one line each and long turns are cut. When the person asks about anything it does not show in full, ' +
|
|
115
|
+
"call recall before you answer: Moxxy's recall tool searches the whole conversation (recall with a query) and " +
|
|
116
|
+
'reads any turn in full (recall with its turn number). Never say you do not know, or offer to look, without ' +
|
|
117
|
+
'searching first. Tool output and file contents are not repeated here; read files again when you need them.';
|
|
118
|
+
/** Without it an agent read the person's message, sent right after the record, as one more turn of the record. */
|
|
119
|
+
const END_OF_RECORD = "End of Moxxy's record. The person's newest message comes next: that is the request to act on.";
|
|
120
|
+
const EARLIER_HEADER = `Earlier in this conversation, from Moxxy's own record of it. ${HISTORY_RULES}`;
|
|
121
|
+
const MISSED_HEADER = 'While you were away, the person went on with this conversation on another connection, so these turns since your ' +
|
|
122
|
+
`last one ran without you. They come from Moxxy's own record of it. ${HISTORY_RULES}`;
|
|
123
|
+
function toTurn(number, turnId, events) {
|
|
124
|
+
const said = [];
|
|
125
|
+
const attached = [];
|
|
126
|
+
const replies = [];
|
|
127
|
+
const tools = [];
|
|
128
|
+
const search = [];
|
|
129
|
+
for (const event of events) {
|
|
130
|
+
if (event.type === 'user_prompt' && event.source === 'user') {
|
|
131
|
+
const trigger = !event.origin ? '' : event.origin.kind === 'agent' ? '(the agent continued by itself) ' : `(started by a ${event.origin.kind}) `;
|
|
132
|
+
said.push(`${trigger}${event.text}`);
|
|
133
|
+
search.push(event.text);
|
|
134
|
+
for (const attachment of event.attachments ?? [])
|
|
135
|
+
attached.push(attachment.name ?? attachment.kind);
|
|
136
|
+
}
|
|
137
|
+
else if (event.type === 'assistant_message' && event.source === 'model' && event.content.trim()) {
|
|
138
|
+
replies.push(event.content);
|
|
139
|
+
search.push(event.content);
|
|
140
|
+
}
|
|
141
|
+
else if (event.type === 'tool_call_requested') {
|
|
142
|
+
tools.push(toolGist(event.name, event.input));
|
|
143
|
+
search.push(`${event.name} ${json(event.input).slice(0, TOOL_INPUT_SEARCH_CHARS)}`);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
search.push(...attached);
|
|
147
|
+
return { number, turnId, said, attached, replies, tools, text: search.join('\n') };
|
|
148
|
+
}
|
|
149
|
+
function renderTurn(turn) {
|
|
150
|
+
const lines = [`### Turn ${turn.number}`, `Person: ${clip(turn.said.join('\n\n'), SAID_CHARS, turn.number)}`];
|
|
151
|
+
if (turn.attached.length > 0)
|
|
152
|
+
lines.push(`Attached: ${turn.attached.join(', ')}`);
|
|
153
|
+
if (turn.replies.length > 0)
|
|
154
|
+
lines.push(`Agent: ${clip(turn.replies.join('\n\n'), REPLIES_CHARS, turn.number)}`);
|
|
155
|
+
if (turn.tools.length > 0) {
|
|
156
|
+
const more = turn.tools.length - TOOLS_LISTED;
|
|
157
|
+
lines.push(`Tools: ${turn.tools.slice(0, TOOLS_LISTED).join('; ')}${more > 0 ? `; and ${more} more` : ''}`);
|
|
158
|
+
}
|
|
159
|
+
return lines.join('\n');
|
|
160
|
+
}
|
|
161
|
+
/** One line per turn; when they do not all fit, the first few and the latest that do, with a gap line between. */
|
|
162
|
+
function renderIndex(turns, budget) {
|
|
163
|
+
const lines = turns.map((turn) => `- turn ${turn.number}: ${oneLine(turn.said.join(' '), INDEX_LINE_CHARS)}`);
|
|
164
|
+
if (lines.join('\n').length <= budget)
|
|
165
|
+
return lines.join('\n');
|
|
166
|
+
const head = lines.slice(0, FIRST_TURNS_KEPT);
|
|
167
|
+
let used = head.join('\n').length;
|
|
168
|
+
const tail = [];
|
|
169
|
+
for (let i = lines.length - 1; i >= FIRST_TURNS_KEPT; i -= 1) {
|
|
170
|
+
const line = lines[i];
|
|
171
|
+
if (line === undefined || used + line.length + 1 > budget)
|
|
172
|
+
break;
|
|
173
|
+
tail.unshift(line);
|
|
174
|
+
used += line.length + 1;
|
|
175
|
+
}
|
|
176
|
+
const from = (turns[head.length]?.number ?? 0);
|
|
177
|
+
const to = turns[turns.length - tail.length - 1]?.number ?? from;
|
|
178
|
+
const gap = `- turns ${from}–${to}: not listed here; recall with a query finds them`;
|
|
179
|
+
return [...head, gap, ...tail].join('\n');
|
|
180
|
+
}
|
|
181
|
+
function toolGist(name, input) {
|
|
182
|
+
if (typeof input === 'object' && input !== null) {
|
|
183
|
+
const fields = input;
|
|
184
|
+
for (const key of ['file_path', 'path', 'command', 'pattern', 'url', 'query', 'filePath']) {
|
|
185
|
+
const value = fields[key];
|
|
186
|
+
if (typeof value === 'string' && value)
|
|
187
|
+
return `${name} ${oneLine(value, TOOL_GIST_CHARS)}`;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
return name;
|
|
191
|
+
}
|
|
192
|
+
/** A word matches from its start; a word's last letters may differ (port, porcie), a number or path must match whole. */
|
|
193
|
+
function searchTerms(query) {
|
|
194
|
+
const words = query.toLowerCase().match(/[\p{L}\p{N}_./:-]+/gu) ?? [];
|
|
195
|
+
const terms = new Set();
|
|
196
|
+
for (const word of words) {
|
|
197
|
+
if (word.length < 2)
|
|
198
|
+
continue;
|
|
199
|
+
const exact = /[\p{N}_./:-]/u.test(word) || word.length <= 3;
|
|
200
|
+
terms.add(exact ? word : word.slice(0, Math.max(3, word.length - 2)));
|
|
201
|
+
}
|
|
202
|
+
return [...terms].map((term) => new RegExp(`(?<![\\p{L}\\p{N}])${escape(term)}`, 'giu'));
|
|
203
|
+
}
|
|
204
|
+
function snippetAt(text, index) {
|
|
205
|
+
const start = Math.max(0, index - SNIPPET_CHARS);
|
|
206
|
+
const end = Math.min(text.length, index + SNIPPET_CHARS);
|
|
207
|
+
return `${start > 0 ? '…' : ''}${oneLine(text.slice(start, end), SNIPPET_CHARS * 2)}${end < text.length ? '…' : ''}`;
|
|
208
|
+
}
|
|
209
|
+
function clip(text, max, turn) {
|
|
210
|
+
return text.length > max ? `${text.slice(0, max)}\n… (the rest: recall({ turn: ${turn} }))` : text;
|
|
211
|
+
}
|
|
212
|
+
function oneLine(text, max) {
|
|
213
|
+
const line = text.replace(/\s+/g, ' ').trim();
|
|
214
|
+
return line.length > max ? `${line.slice(0, max - 1)}…` : line;
|
|
215
|
+
}
|
|
216
|
+
function escape(text) {
|
|
217
|
+
return text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
218
|
+
}
|
|
219
|
+
function json(value) {
|
|
220
|
+
try {
|
|
221
|
+
return typeof value === 'string' ? value : (JSON.stringify(value) ?? '');
|
|
222
|
+
}
|
|
223
|
+
catch {
|
|
224
|
+
return String(value);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
//# sourceMappingURL=conversation-history.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conversation-history.js","sourceRoot":"","sources":["../src/conversation-history.ts"],"names":[],"mappings":"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"}
|
package/dist/cron.d.ts
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tiny POSIX-style 5-field cron parser.
|
|
3
|
+
*
|
|
4
|
+
* ┌───────────── minute (0-59)
|
|
5
|
+
* │ ┌─────────── hour (0-23)
|
|
6
|
+
* │ │ ┌───────── day-of-month (1-31)
|
|
7
|
+
* │ │ │ ┌─────── month (1-12)
|
|
8
|
+
* │ │ │ │ ┌───── day-of-week (0-6, Sunday=0)
|
|
9
|
+
* * * * * *
|
|
10
|
+
*
|
|
11
|
+
* Each field supports:
|
|
12
|
+
* - `*` — any value in range
|
|
13
|
+
* - `n` — literal
|
|
14
|
+
* - `a-b` — inclusive range
|
|
15
|
+
* - `a,b,c` — list
|
|
16
|
+
* - `*\/n` — every n
|
|
17
|
+
* - `a-b/n` — every n within a range
|
|
18
|
+
*
|
|
19
|
+
* `nextFireTime(expr, after)` walks forward minute-by-minute (with cheap
|
|
20
|
+
* field-by-field jumps) until every field matches, capped at a year
|
|
21
|
+
* lookahead. Returns null if no fire is reachable (impossible expression
|
|
22
|
+
* like `0 0 31 2 *`).
|
|
23
|
+
*
|
|
24
|
+
* Standard cron quirk: when both DOM and DOW are restricted, vixie-cron
|
|
25
|
+
* matches on EITHER. We follow that convention.
|
|
26
|
+
*/
|
|
27
|
+
interface FieldSpec {
|
|
28
|
+
readonly values: ReadonlySet<number>;
|
|
29
|
+
readonly restricted: boolean;
|
|
30
|
+
}
|
|
31
|
+
export interface ParsedCron {
|
|
32
|
+
readonly minute: FieldSpec;
|
|
33
|
+
readonly hour: FieldSpec;
|
|
34
|
+
readonly dom: FieldSpec;
|
|
35
|
+
readonly month: FieldSpec;
|
|
36
|
+
readonly dow: FieldSpec;
|
|
37
|
+
}
|
|
38
|
+
export declare function parseCron(expr: string): ParsedCron;
|
|
39
|
+
export declare function isValidCron(expr: string): boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Whether `tz` is an IANA zone the runtime's `Intl` accepts. A non-IANA
|
|
42
|
+
* string (e.g. 'PST', 'Mars/Phobos') makes `Intl.DateTimeFormat` throw a
|
|
43
|
+
* RangeError. `nextFireTime` would otherwise inherit that throw deep inside
|
|
44
|
+
* the poller tick (outside its per-entry try/catch), aborting evaluation of
|
|
45
|
+
* every schedule positioned after the bad one. We reject the zone at the
|
|
46
|
+
* trust boundary instead. `undefined`/'local' mean system-local (always ok).
|
|
47
|
+
*/
|
|
48
|
+
export declare function isValidTimeZone(tz: string | undefined): boolean;
|
|
49
|
+
/**
|
|
50
|
+
* Minute-precision walk forward from `after` (exclusive) until every
|
|
51
|
+
* field matches. Operates in the caller-supplied IANA timezone via
|
|
52
|
+
* `Intl.DateTimeFormat` — defaults to system local. The walk is
|
|
53
|
+
* bounded at 1-year so a structurally-impossible expression returns
|
|
54
|
+
* null instead of looping forever.
|
|
55
|
+
*/
|
|
56
|
+
export declare function nextFireTime(expr: string, after: Date, timeZone?: string): Date | null;
|
|
57
|
+
export {};
|
|
58
|
+
//# sourceMappingURL=cron.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cron.d.ts","sourceRoot":"","sources":["../src/cron.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAIH,UAAU,SAAS;IACjB,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACrC,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;CAC9B;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,GAAG,EAAE,SAAS,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;IAC1B,QAAQ,CAAC,GAAG,EAAE,SAAS,CAAC;CACzB;AAwDD,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAalD;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAOjD;AAsCD;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAQ/D;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,IAAI,EACX,QAAQ,CAAC,EAAE,MAAM,GAChB,IAAI,GAAG,IAAI,CAkEb"}
|
package/dist/cron.js
ADDED
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tiny POSIX-style 5-field cron parser.
|
|
3
|
+
*
|
|
4
|
+
* ┌───────────── minute (0-59)
|
|
5
|
+
* │ ┌─────────── hour (0-23)
|
|
6
|
+
* │ │ ┌───────── day-of-month (1-31)
|
|
7
|
+
* │ │ │ ┌─────── month (1-12)
|
|
8
|
+
* │ │ │ │ ┌───── day-of-week (0-6, Sunday=0)
|
|
9
|
+
* * * * * *
|
|
10
|
+
*
|
|
11
|
+
* Each field supports:
|
|
12
|
+
* - `*` — any value in range
|
|
13
|
+
* - `n` — literal
|
|
14
|
+
* - `a-b` — inclusive range
|
|
15
|
+
* - `a,b,c` — list
|
|
16
|
+
* - `*\/n` — every n
|
|
17
|
+
* - `a-b/n` — every n within a range
|
|
18
|
+
*
|
|
19
|
+
* `nextFireTime(expr, after)` walks forward minute-by-minute (with cheap
|
|
20
|
+
* field-by-field jumps) until every field matches, capped at a year
|
|
21
|
+
* lookahead. Returns null if no fire is reachable (impossible expression
|
|
22
|
+
* like `0 0 31 2 *`).
|
|
23
|
+
*
|
|
24
|
+
* Standard cron quirk: when both DOM and DOW are restricted, vixie-cron
|
|
25
|
+
* matches on EITHER. We follow that convention.
|
|
26
|
+
*/
|
|
27
|
+
import { assertDefined } from './assert.js';
|
|
28
|
+
const FIELD_RANGES = {
|
|
29
|
+
minute: { min: 0, max: 59 },
|
|
30
|
+
hour: { min: 0, max: 23 },
|
|
31
|
+
dom: { min: 1, max: 31 },
|
|
32
|
+
month: { min: 1, max: 12 },
|
|
33
|
+
dow: { min: 0, max: 6 },
|
|
34
|
+
};
|
|
35
|
+
function parseField(raw, range, fieldName) {
|
|
36
|
+
const values = new Set();
|
|
37
|
+
const restricted = raw !== '*' && !raw.startsWith('*/');
|
|
38
|
+
for (const piece of raw.split(',')) {
|
|
39
|
+
const [rangePart, stepPart] = piece.split('/');
|
|
40
|
+
if (rangePart === undefined)
|
|
41
|
+
throw new Error(`empty term in ${fieldName}: "${raw}"`);
|
|
42
|
+
const step = stepPart ? toIntStrict(stepPart, fieldName) : 1;
|
|
43
|
+
if (step < 1)
|
|
44
|
+
throw new Error(`step must be >= 1 in ${fieldName}: "${raw}"`);
|
|
45
|
+
let lo;
|
|
46
|
+
let hi;
|
|
47
|
+
if (rangePart === '*') {
|
|
48
|
+
lo = range.min;
|
|
49
|
+
hi = range.max;
|
|
50
|
+
}
|
|
51
|
+
else if (rangePart.includes('-')) {
|
|
52
|
+
const [a, b] = rangePart.split('-');
|
|
53
|
+
// A string containing '-' always splits into >= 2 parts, so both bounds
|
|
54
|
+
// are present by construction (empty strings are caught by toIntStrict).
|
|
55
|
+
assertDefined(a, 'range lower bound (rangePart contains "-")');
|
|
56
|
+
assertDefined(b, 'range upper bound (rangePart contains "-")');
|
|
57
|
+
lo = toIntStrict(a, fieldName);
|
|
58
|
+
hi = toIntStrict(b, fieldName);
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
lo = toIntStrict(rangePart, fieldName);
|
|
62
|
+
hi = lo;
|
|
63
|
+
}
|
|
64
|
+
if (lo < range.min || hi > range.max || lo > hi) {
|
|
65
|
+
throw new Error(`out-of-range term "${piece}" in ${fieldName} (allowed ${range.min}-${range.max})`);
|
|
66
|
+
}
|
|
67
|
+
for (let v = lo; v <= hi; v += step)
|
|
68
|
+
values.add(v);
|
|
69
|
+
}
|
|
70
|
+
return { values, restricted };
|
|
71
|
+
}
|
|
72
|
+
function toIntStrict(s, fieldName) {
|
|
73
|
+
if (!/^-?\d+$/.test(s))
|
|
74
|
+
throw new Error(`non-integer "${s}" in ${fieldName}`);
|
|
75
|
+
return Number(s);
|
|
76
|
+
}
|
|
77
|
+
export function parseCron(expr) {
|
|
78
|
+
const fields = expr.trim().split(/\s+/);
|
|
79
|
+
if (fields.length !== 5) {
|
|
80
|
+
throw new Error(`cron expression must have 5 fields, got ${fields.length}: "${expr}"`);
|
|
81
|
+
}
|
|
82
|
+
const [minute, hour, dom, month, dow] = fields;
|
|
83
|
+
return {
|
|
84
|
+
minute: parseField(minute, FIELD_RANGES.minute, 'minute'),
|
|
85
|
+
hour: parseField(hour, FIELD_RANGES.hour, 'hour'),
|
|
86
|
+
dom: parseField(dom, FIELD_RANGES.dom, 'dom'),
|
|
87
|
+
month: parseField(month, FIELD_RANGES.month, 'month'),
|
|
88
|
+
dow: parseField(dow, FIELD_RANGES.dow, 'dow'),
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
export function isValidCron(expr) {
|
|
92
|
+
try {
|
|
93
|
+
parseCron(expr);
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
// Calendar maximum day-of-month per month (1-12). February uses 29 to allow
|
|
101
|
+
// leap-year Feb 29 fires; non-leap years are then handled by the normal walk.
|
|
102
|
+
const MAX_DOM_BY_MONTH = {
|
|
103
|
+
1: 31, 2: 29, 3: 31, 4: 30, 5: 31, 6: 30,
|
|
104
|
+
7: 31, 8: 31, 9: 30, 10: 31, 11: 30, 12: 31,
|
|
105
|
+
};
|
|
106
|
+
/**
|
|
107
|
+
* Cheap, zone-independent structural-impossibility check. Some cron
|
|
108
|
+
* expressions can never fire because their day-of-month is larger than every
|
|
109
|
+
* candidate month allows (e.g. `0 0 30 2 *` — Feb never has a 30th, or
|
|
110
|
+
* `0 0 31 4 *` — April has no 31st). Without this, an explicit-IANA-zone walk
|
|
111
|
+
* for such an expression advances minute-by-minute through the full 366-day cap
|
|
112
|
+
* (~527k `Intl.formatToParts` calls, ~2s of blocked event loop) only to return
|
|
113
|
+
* null. The DOM/DOW OR-semantics quirk means this is only safe to declare
|
|
114
|
+
* impossible when DOW is unrestricted (`*`): if DOW is restricted the day can
|
|
115
|
+
* still match via the weekday arm regardless of DOM. We check exactly the case
|
|
116
|
+
* the walk is slowest on — a restricted DOM whose smallest value exceeds the
|
|
117
|
+
* largest day any selected month can hold — and bail to "no fire" instantly.
|
|
118
|
+
*/
|
|
119
|
+
function isStructurallyImpossible(cron) {
|
|
120
|
+
// OR-semantics: a restricted DOW can satisfy the day on its own, so DOM being
|
|
121
|
+
// unreachable does not make the expression impossible. Only decide when DOW
|
|
122
|
+
// is unrestricted (every weekday allowed) and DOM is restricted.
|
|
123
|
+
if (cron.dow.restricted || !cron.dom.restricted)
|
|
124
|
+
return false;
|
|
125
|
+
const minDom = Math.min(...cron.dom.values);
|
|
126
|
+
let maxAllowed = 0;
|
|
127
|
+
for (const month of cron.month.values) {
|
|
128
|
+
const cap = MAX_DOM_BY_MONTH[month] ?? 31;
|
|
129
|
+
if (cap > maxAllowed)
|
|
130
|
+
maxAllowed = cap;
|
|
131
|
+
}
|
|
132
|
+
// If the smallest requested day-of-month is larger than the biggest day any
|
|
133
|
+
// selected month can ever hold, no instant can match — impossible.
|
|
134
|
+
return minDom > maxAllowed;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Whether `tz` is an IANA zone the runtime's `Intl` accepts. A non-IANA
|
|
138
|
+
* string (e.g. 'PST', 'Mars/Phobos') makes `Intl.DateTimeFormat` throw a
|
|
139
|
+
* RangeError. `nextFireTime` would otherwise inherit that throw deep inside
|
|
140
|
+
* the poller tick (outside its per-entry try/catch), aborting evaluation of
|
|
141
|
+
* every schedule positioned after the bad one. We reject the zone at the
|
|
142
|
+
* trust boundary instead. `undefined`/'local' mean system-local (always ok).
|
|
143
|
+
*/
|
|
144
|
+
export function isValidTimeZone(tz) {
|
|
145
|
+
if (tz === undefined || tz === 'local')
|
|
146
|
+
return true;
|
|
147
|
+
try {
|
|
148
|
+
new Intl.DateTimeFormat(undefined, { timeZone: tz });
|
|
149
|
+
return true;
|
|
150
|
+
}
|
|
151
|
+
catch {
|
|
152
|
+
return false;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Minute-precision walk forward from `after` (exclusive) until every
|
|
157
|
+
* field matches. Operates in the caller-supplied IANA timezone via
|
|
158
|
+
* `Intl.DateTimeFormat` — defaults to system local. The walk is
|
|
159
|
+
* bounded at 1-year so a structurally-impossible expression returns
|
|
160
|
+
* null instead of looping forever.
|
|
161
|
+
*/
|
|
162
|
+
export function nextFireTime(expr, after, timeZone) {
|
|
163
|
+
const cron = parseCron(expr);
|
|
164
|
+
// Defense in depth: a malformed/legacy timeZone that slipped past the
|
|
165
|
+
// trust-boundary validation would make `Intl.DateTimeFormat` throw deep in
|
|
166
|
+
// the walk — outside the poller's per-entry guard, which would abort every
|
|
167
|
+
// later schedule's evaluation. Treat an unusable zone as "no reachable fire"
|
|
168
|
+
// (null) so the entry is simply never due, matching how callers handle null.
|
|
169
|
+
if (!isValidTimeZone(timeZone))
|
|
170
|
+
return null;
|
|
171
|
+
// Bail instantly on a structurally-impossible expression (e.g. Feb 30,
|
|
172
|
+
// Apr 31) BEFORE the walk. For an explicit IANA zone the walk would
|
|
173
|
+
// otherwise advance minute-by-minute through the full 366-day cap (~527k
|
|
174
|
+
// `Intl.formatToParts` calls, ~2s of blocked event loop) just to return
|
|
175
|
+
// null — a self-inflicted DoS one typo'd skill could trigger every time its
|
|
176
|
+
// baseline changes. This check is calendar-fact-only, so it is correct in
|
|
177
|
+
// any zone.
|
|
178
|
+
if (isStructurallyImpossible(cron))
|
|
179
|
+
return null;
|
|
180
|
+
// Start at after + 1 minute, zero seconds.
|
|
181
|
+
const start = new Date(after.getTime() + 60_000);
|
|
182
|
+
start.setSeconds(0, 0);
|
|
183
|
+
const limit = new Date(start.getTime() + 366 * 24 * 60 * 60_000);
|
|
184
|
+
// The field-by-field jump helpers mutate the cursor with system-local
|
|
185
|
+
// `Date` methods, so they are only correct when matching is also done in
|
|
186
|
+
// the host's local zone. For an explicit (non-local) IANA zone we walk
|
|
187
|
+
// minute-by-minute on the absolute instant instead — slower, but advancing
|
|
188
|
+
// the cursor by a fixed 60_000 ms is zone-independent, whereas the local
|
|
189
|
+
// setHours/setDate jumps would land on the wrong wall-clock instant in the
|
|
190
|
+
// target zone (off-by-offset / DST errors). The 1-year cap still bounds it.
|
|
191
|
+
const explicitZone = !!timeZone && timeZone !== 'local';
|
|
192
|
+
const cursor = new Date(start);
|
|
193
|
+
while (cursor <= limit) {
|
|
194
|
+
const parts = decomposeInZone(cursor, timeZone);
|
|
195
|
+
if (!cron.month.values.has(parts.month)) {
|
|
196
|
+
if (explicitZone) {
|
|
197
|
+
cursor.setTime(cursor.getTime() + 60_000);
|
|
198
|
+
}
|
|
199
|
+
else {
|
|
200
|
+
// Jump to the first day of the next candidate month.
|
|
201
|
+
jumpToNextMonth(cursor, parts, cron.month.values, timeZone);
|
|
202
|
+
}
|
|
203
|
+
continue;
|
|
204
|
+
}
|
|
205
|
+
const domOk = cron.dom.values.has(parts.dom);
|
|
206
|
+
const dowOk = cron.dow.values.has(parts.dow);
|
|
207
|
+
// Vixie-cron OR semantics when both DOM and DOW are restricted.
|
|
208
|
+
const dayMatches = cron.dom.restricted && cron.dow.restricted
|
|
209
|
+
? domOk || dowOk
|
|
210
|
+
: domOk && dowOk;
|
|
211
|
+
if (!dayMatches) {
|
|
212
|
+
if (explicitZone)
|
|
213
|
+
cursor.setTime(cursor.getTime() + 60_000);
|
|
214
|
+
else
|
|
215
|
+
jumpToNextDay(cursor, timeZone);
|
|
216
|
+
continue;
|
|
217
|
+
}
|
|
218
|
+
if (!cron.hour.values.has(parts.hour)) {
|
|
219
|
+
if (explicitZone)
|
|
220
|
+
cursor.setTime(cursor.getTime() + 60_000);
|
|
221
|
+
else
|
|
222
|
+
jumpToNextHour(cursor, timeZone);
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
225
|
+
if (!cron.minute.values.has(parts.minute)) {
|
|
226
|
+
if (explicitZone)
|
|
227
|
+
cursor.setTime(cursor.getTime() + 60_000);
|
|
228
|
+
else
|
|
229
|
+
cursor.setMinutes(cursor.getMinutes() + 1, 0, 0);
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
return new Date(cursor.getTime());
|
|
233
|
+
}
|
|
234
|
+
return null;
|
|
235
|
+
}
|
|
236
|
+
// Memoized Intl.DateTimeFormat per IANA zone. Formatters are stateless, so
|
|
237
|
+
// caching them across the (potentially long) minute-walk avoids re-allocating
|
|
238
|
+
// one on every cursor step for explicit-zone crons.
|
|
239
|
+
const formatterCache = new Map();
|
|
240
|
+
function formatterFor(timeZone) {
|
|
241
|
+
let fmt = formatterCache.get(timeZone);
|
|
242
|
+
if (!fmt) {
|
|
243
|
+
fmt = new Intl.DateTimeFormat('en-US', {
|
|
244
|
+
timeZone,
|
|
245
|
+
year: 'numeric',
|
|
246
|
+
month: '2-digit',
|
|
247
|
+
day: '2-digit',
|
|
248
|
+
weekday: 'short',
|
|
249
|
+
hour: '2-digit',
|
|
250
|
+
minute: '2-digit',
|
|
251
|
+
hour12: false,
|
|
252
|
+
});
|
|
253
|
+
formatterCache.set(timeZone, fmt);
|
|
254
|
+
}
|
|
255
|
+
return fmt;
|
|
256
|
+
}
|
|
257
|
+
function decomposeInZone(d, timeZone) {
|
|
258
|
+
// Local time decomposition. We deliberately default to system-local —
|
|
259
|
+
// a user saying "every day at 9 AM" overwhelmingly means their wall
|
|
260
|
+
// clock, not UTC. Callers that need UTC pass timeZone='UTC'.
|
|
261
|
+
if (!timeZone || timeZone === 'local') {
|
|
262
|
+
return {
|
|
263
|
+
year: d.getFullYear(),
|
|
264
|
+
month: d.getMonth() + 1,
|
|
265
|
+
dom: d.getDate(),
|
|
266
|
+
dow: d.getDay(),
|
|
267
|
+
hour: d.getHours(),
|
|
268
|
+
minute: d.getMinutes(),
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
// Intl-based decomposition for explicit zones. A formatter is stateless,
|
|
272
|
+
// so memoize one per IANA zone — `nextFireTime` can walk many minute steps
|
|
273
|
+
// for a sparse cron and was previously allocating a fresh formatter on each
|
|
274
|
+
// step. Correctness is unchanged; only the per-step allocation is removed.
|
|
275
|
+
const fmt = formatterFor(timeZone);
|
|
276
|
+
const parts = {};
|
|
277
|
+
for (const part of fmt.formatToParts(d))
|
|
278
|
+
parts[part.type] = part.value;
|
|
279
|
+
const weekdayMap = { Sun: 0, Mon: 1, Tue: 2, Wed: 3, Thu: 4, Fri: 5, Sat: 6 };
|
|
280
|
+
// The formatter is configured with `weekday: 'short'`, so formatToParts
|
|
281
|
+
// always emits a weekday part, so its presence is impossible by construction.
|
|
282
|
+
const weekday = parts.weekday;
|
|
283
|
+
assertDefined(weekday, 'formatToParts includes weekday (formatter sets weekday: short)');
|
|
284
|
+
return {
|
|
285
|
+
year: Number(parts.year),
|
|
286
|
+
month: Number(parts.month),
|
|
287
|
+
dom: Number(parts.day),
|
|
288
|
+
dow: weekdayMap[weekday] ?? 0,
|
|
289
|
+
hour: Number(parts.hour) % 24,
|
|
290
|
+
minute: Number(parts.minute),
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
function jumpToNextMonth(cursor, current, validMonths, _timeZone) {
|
|
294
|
+
// Find next valid month >= current+1; wraps to next year if needed.
|
|
295
|
+
let nextMonth = current.month + 1;
|
|
296
|
+
let yearDelta = 0;
|
|
297
|
+
while (!validMonths.has(((nextMonth - 1) % 12) + 1)) {
|
|
298
|
+
nextMonth += 1;
|
|
299
|
+
if (nextMonth > 24) {
|
|
300
|
+
// Pathological: walk hit a wall. Caller's outer loop will give up
|
|
301
|
+
// at the 1-year limit.
|
|
302
|
+
cursor.setFullYear(cursor.getFullYear() + 1);
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
while (nextMonth > 12) {
|
|
307
|
+
nextMonth -= 12;
|
|
308
|
+
yearDelta += 1;
|
|
309
|
+
}
|
|
310
|
+
cursor.setFullYear(cursor.getFullYear() + yearDelta, nextMonth - 1, 1);
|
|
311
|
+
cursor.setHours(0, 0, 0, 0);
|
|
312
|
+
}
|
|
313
|
+
function jumpToNextDay(cursor, _timeZone) {
|
|
314
|
+
cursor.setDate(cursor.getDate() + 1);
|
|
315
|
+
cursor.setHours(0, 0, 0, 0);
|
|
316
|
+
}
|
|
317
|
+
function jumpToNextHour(cursor, _timeZone) {
|
|
318
|
+
cursor.setHours(cursor.getHours() + 1, 0, 0, 0);
|
|
319
|
+
}
|
|
320
|
+
//# sourceMappingURL=cron.js.map
|
package/dist/cron.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cron.js","sourceRoot":"","sources":["../src/cron.ts"],"names":[],"mappings":"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"}
|