@corenel/web-ui 0.2.0 → 0.3.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/AskUser.js +1 -1
- package/dist/AskUser.js.map +1 -1
- package/dist/CommandTray.d.ts +21 -0
- package/dist/CommandTray.d.ts.map +1 -0
- package/dist/CommandTray.js +102 -0
- package/dist/CommandTray.js.map +1 -0
- package/dist/Composer.d.ts +11 -1
- package/dist/Composer.d.ts.map +1 -1
- package/dist/Composer.js +76 -3
- package/dist/Composer.js.map +1 -1
- package/dist/ContextBar.d.ts.map +1 -1
- package/dist/ContextBar.js +7 -1
- package/dist/ContextBar.js.map +1 -1
- package/dist/ProcessDock.d.ts +45 -0
- package/dist/ProcessDock.d.ts.map +1 -0
- package/dist/ProcessDock.js +150 -0
- package/dist/ProcessDock.js.map +1 -0
- package/dist/TodoBar.d.ts +3 -0
- package/dist/TodoBar.d.ts.map +1 -0
- package/dist/TodoBar.js +163 -0
- package/dist/TodoBar.js.map +1 -0
- package/dist/Transcript.js +1 -1
- package/dist/Transcript.js.map +1 -1
- package/dist/agentChat/AgentChat.d.ts +10 -0
- package/dist/agentChat/AgentChat.d.ts.map +1 -1
- package/dist/agentChat/AgentChat.js +69 -8
- package/dist/agentChat/AgentChat.js.map +1 -1
- package/dist/agentChat/OptionsDrawer.js +5 -5
- package/dist/agentChat/OptionsDrawer.js.map +1 -1
- package/dist/agentChat/controller.d.ts +23 -0
- package/dist/agentChat/controller.d.ts.map +1 -1
- package/dist/agentChat/controller.js.map +1 -1
- package/dist/commandTurn.d.ts +47 -0
- package/dist/commandTurn.d.ts.map +1 -0
- package/dist/commandTurn.js +64 -0
- package/dist/commandTurn.js.map +1 -0
- package/dist/composerHistory.d.ts +10 -0
- package/dist/composerHistory.d.ts.map +1 -0
- package/dist/composerHistory.js +44 -0
- package/dist/composerHistory.js.map +1 -0
- package/dist/sendLater/SendLater.d.ts +31 -0
- package/dist/sendLater/SendLater.d.ts.map +1 -0
- package/dist/sendLater/SendLater.js +145 -0
- package/dist/sendLater/SendLater.js.map +1 -0
- package/dist/sendLater/queue.d.ts +69 -0
- package/dist/sendLater/queue.d.ts.map +1 -0
- package/dist/sendLater/queue.js +216 -0
- package/dist/sendLater/queue.js.map +1 -0
- package/package.json +5 -5
|
@@ -30,6 +30,16 @@ export interface ControllerRecordedEvent {
|
|
|
30
30
|
at: number;
|
|
31
31
|
ev: unknown;
|
|
32
32
|
}
|
|
33
|
+
/** One step of an agent-maintained task list.
|
|
34
|
+
*
|
|
35
|
+
* OPTIONAL on the state below, because only some engines keep one: a proxied
|
|
36
|
+
* ACP agent reports its plan on the session stream, while our own loop tracks
|
|
37
|
+
* todos through a tool. An engine with no plan simply never sets it. */
|
|
38
|
+
export interface ControllerPlanEntry {
|
|
39
|
+
content: string;
|
|
40
|
+
status: 'pending' | 'in_progress' | 'completed';
|
|
41
|
+
priority?: string;
|
|
42
|
+
}
|
|
33
43
|
/** What AgentChat renders of a session — structurally satisfied by the engine's
|
|
34
44
|
* SessionState (extra fields on the real state are fine). */
|
|
35
45
|
export interface ControllerSessionState {
|
|
@@ -43,9 +53,13 @@ export interface ControllerSessionState {
|
|
|
43
53
|
mode: string;
|
|
44
54
|
input: string;
|
|
45
55
|
attachments: string[];
|
|
56
|
+
/** `requester` says who raised it — the run loop, or a command the user typed.
|
|
57
|
+
* Optional so an engine that only ever asks on the agent's behalf need not
|
|
58
|
+
* set it; absent reads as 'agent'. */
|
|
46
59
|
pendingPerm: {
|
|
47
60
|
tool: string;
|
|
48
61
|
summary: string;
|
|
62
|
+
requester?: 'agent' | 'you';
|
|
49
63
|
} | null;
|
|
50
64
|
pendingAsk: {
|
|
51
65
|
questions: AskQuestion[];
|
|
@@ -58,9 +72,18 @@ export interface ControllerSessionState {
|
|
|
58
72
|
message: string;
|
|
59
73
|
action: string;
|
|
60
74
|
}[];
|
|
75
|
+
/** A console command still running, or null. Optional so a surface whose
|
|
76
|
+
* controller predates it (the ACP chat controller) still satisfies the type
|
|
77
|
+
* rather than being forced to model a command channel it does not have. */
|
|
78
|
+
pendingCommand?: {
|
|
79
|
+
command: string;
|
|
80
|
+
startedAt: number;
|
|
81
|
+
} | null;
|
|
61
82
|
degradedModel: string | null;
|
|
62
83
|
/** Raw event stream of the active session, for a host-injected live timeline. */
|
|
63
84
|
recEvents: ControllerRecordedEvent[];
|
|
85
|
+
/** The agent's current task list, when it publishes one. */
|
|
86
|
+
plan?: ControllerPlanEntry[];
|
|
64
87
|
}
|
|
65
88
|
/** Structural view of the multi-session agent engine. @corenel/tools-web's
|
|
66
89
|
* AgentRuntime satisfies this WITHOUT web-ui importing it (the Phase 3
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../agentChat/controller.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEjE;gFACgF;AAChF,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB;;;;yDAIqD;IACrD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,WAAW,CAAC;IAC5B,aAAa,CAAC,EAAE,OAAO,GAAG,YAAY,CAAC;CACxC;AAED,MAAM,WAAW,kBAAkB;IAAG,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IAAC,EAAE,CAAC,EAAE,MAAM,CAAA;CAAE;AAEjK;uFACuF;AACvF,MAAM,WAAW,uBAAuB;IAAG,EAAE,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,OAAO,CAAA;CAAE;AAEpE;6DAC6D;AAC7D,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,gBAAgB,EAAE,CAAC;IAC1B,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,kBAAkB,EAAE,CAAA;KAAE,GAAG,IAAI,CAAC;IAC3D,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,WAAW,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../agentChat/controller.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"controller.js","sourceRoot":"","sources":["../../agentChat/controller.ts"],"names":[],"mappings":"AAAA;;;;kCAIkC;AAClC,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"controller.js","sourceRoot":"","sources":["../../agentChat/controller.ts"],"names":[],"mappings":"AAAA;;;;kCAIkC;AAClC,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AA4F9C,sFAAsF;AACtF,MAAM,UAAU,oBAAoB,CAAyB,UAAqC,EAAE,EAAU;IAC5G,MAAM,CAAC,EAAE,KAAK,CAAC,GAAG,UAAU,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IACtD,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,EAAE;YAAE,OAAO;QAChB,MAAM,KAAK,GAAG,UAAU,CAAC,SAAS,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;QAC9C,KAAK,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACzB,OAAO,KAAK,CAAC;IACf,CAAC,EAAE,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,CAAC;IACrB,OAAO,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACjC,CAAC;AAED,2EAA2E;AAC3E,MAAM,UAAU,mBAAmB,CAAyB,UAAqC;IAC/F,MAAM,CAAC,CAAC,EAAE,KAAK,CAAC,GAAG,UAAU,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IACvD,SAAS,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,eAAe,CAAC,KAAK,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC;IACjE,OAAO,CAAC,CAAC;AACX,CAAC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { ConversationTurn } from '@corenel/harness/conversation';
|
|
2
|
+
/** The name recordCommand writes. Not a general tool: nothing else may claim it. */
|
|
3
|
+
export declare const COMMAND_TOOL = "console_command";
|
|
4
|
+
export interface CommandTurnInfo {
|
|
5
|
+
turnId: string;
|
|
6
|
+
command: string;
|
|
7
|
+
output: string;
|
|
8
|
+
ok: boolean;
|
|
9
|
+
/** Whether the user has promoted it into context (the Keep decision). */
|
|
10
|
+
kept: boolean;
|
|
11
|
+
/** True for a `>!` shell line, which is recorded with its `!` intact. It
|
|
12
|
+
* matters because a shell command has a SECOND representation — the process
|
|
13
|
+
* card — and showing both put three stacked boxes on screen for one
|
|
14
|
+
* keystroke. */
|
|
15
|
+
shell: boolean;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* The command a turn records, or null when it is an ordinary turn.
|
|
19
|
+
*
|
|
20
|
+
* Tolerant on the way in: a session log is durable data that may have been
|
|
21
|
+
* written by an older build, so anything malformed reads as "not a command
|
|
22
|
+
* turn" rather than throwing inside a render.
|
|
23
|
+
*/
|
|
24
|
+
export declare function readCommandTurn(turn: ConversationTurn): CommandTurnInfo | null;
|
|
25
|
+
/**
|
|
26
|
+
* The command turn the tray should offer, or null.
|
|
27
|
+
*
|
|
28
|
+
* Only the LAST one, and only while it is un-kept — which is the whole of
|
|
29
|
+
* "output evaporates on the next command". A kept command has moved into the
|
|
30
|
+
* transcript and must not also sit in the tray.
|
|
31
|
+
*
|
|
32
|
+
* SHELL LINES ARE SKIPPED ENTIRELY. A `>!` command already has a representation
|
|
33
|
+
* — the process card, which carries its live output, how it ended, and its own
|
|
34
|
+
* Keep. A tray entry beside it was a third box on screen for one keystroke,
|
|
35
|
+
* whose only content was a pointer to the second. Skipped here rather than
|
|
36
|
+
* suppressed at the source, because the turn itself must still be RECORDED: it
|
|
37
|
+
* is what persists the command to the session log and what Up recalls.
|
|
38
|
+
*/
|
|
39
|
+
export declare function trayCommand(turns: ConversationTurn[]): CommandTurnInfo | null;
|
|
40
|
+
/**
|
|
41
|
+
* The turns the transcript should render: everything except un-kept commands.
|
|
42
|
+
*
|
|
43
|
+
* An un-kept command is not in context, so showing it in the transcript would
|
|
44
|
+
* claim the agent can see something it cannot.
|
|
45
|
+
*/
|
|
46
|
+
export declare function transcriptTurns(turns: ConversationTurn[]): ConversationTurn[];
|
|
47
|
+
//# sourceMappingURL=commandTurn.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commandTurn.d.ts","sourceRoot":"","sources":["../commandTurn.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAEtE,oFAAoF;AACpF,eAAO,MAAM,YAAY,oBAAoB,CAAC;AAE9C,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,EAAE,EAAE,OAAO,CAAC;IACZ,yEAAyE;IACzE,IAAI,EAAE,OAAO,CAAC;IACd;;;oBAGgB;IAChB,KAAK,EAAE,OAAO,CAAC;CAChB;AAQD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,gBAAgB,GAAG,eAAe,GAAG,IAAI,CAkB9E;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,EAAE,GAAG,eAAe,GAAG,IAAI,CAO7E;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,gBAAgB,EAAE,GAAG,gBAAgB,EAAE,CAE7E"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/** The name recordCommand writes. Not a general tool: nothing else may claim it. */
|
|
2
|
+
export const COMMAND_TOOL = 'console_command';
|
|
3
|
+
/** The marker that makes a recorded command line a shell line. Kept in step with
|
|
4
|
+
* the host's SHELL_PREFIX by a test. */
|
|
5
|
+
const SHELL_MARK = '!';
|
|
6
|
+
/**
|
|
7
|
+
* The command a turn records, or null when it is an ordinary turn.
|
|
8
|
+
*
|
|
9
|
+
* Tolerant on the way in: a session log is durable data that may have been
|
|
10
|
+
* written by an older build, so anything malformed reads as "not a command
|
|
11
|
+
* turn" rather than throwing inside a render.
|
|
12
|
+
*/
|
|
13
|
+
export function readCommandTurn(turn) {
|
|
14
|
+
const first = turn.messages[0];
|
|
15
|
+
const call = first?.tool_calls?.[0];
|
|
16
|
+
if (call?.function?.name !== COMMAND_TOOL)
|
|
17
|
+
return null;
|
|
18
|
+
let command = '';
|
|
19
|
+
let ok = true;
|
|
20
|
+
try {
|
|
21
|
+
const args = JSON.parse(call.function.arguments || '{}');
|
|
22
|
+
command = typeof args.command === 'string' ? args.command : '';
|
|
23
|
+
// Absent means an older record that predates the flag. Treating that as
|
|
24
|
+
// success is right: a failure was always written into the output text too.
|
|
25
|
+
ok = args.ok !== false;
|
|
26
|
+
}
|
|
27
|
+
catch { /* unparseable arguments: keep the empty command */ }
|
|
28
|
+
const result = turn.messages[1];
|
|
29
|
+
const output = typeof result?.content === 'string' ? result.content : '';
|
|
30
|
+
return { turnId: turn.id, command, output, ok, kept: turn.included, shell: command.startsWith(SHELL_MARK) };
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* The command turn the tray should offer, or null.
|
|
34
|
+
*
|
|
35
|
+
* Only the LAST one, and only while it is un-kept — which is the whole of
|
|
36
|
+
* "output evaporates on the next command". A kept command has moved into the
|
|
37
|
+
* transcript and must not also sit in the tray.
|
|
38
|
+
*
|
|
39
|
+
* SHELL LINES ARE SKIPPED ENTIRELY. A `>!` command already has a representation
|
|
40
|
+
* — the process card, which carries its live output, how it ended, and its own
|
|
41
|
+
* Keep. A tray entry beside it was a third box on screen for one keystroke,
|
|
42
|
+
* whose only content was a pointer to the second. Skipped here rather than
|
|
43
|
+
* suppressed at the source, because the turn itself must still be RECORDED: it
|
|
44
|
+
* is what persists the command to the session log and what Up recalls.
|
|
45
|
+
*/
|
|
46
|
+
export function trayCommand(turns) {
|
|
47
|
+
for (let i = turns.length - 1; i >= 0; i--) {
|
|
48
|
+
const info = readCommandTurn(turns[i]);
|
|
49
|
+
if (!info || info.shell)
|
|
50
|
+
continue;
|
|
51
|
+
return info.kept ? null : info;
|
|
52
|
+
}
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* The turns the transcript should render: everything except un-kept commands.
|
|
57
|
+
*
|
|
58
|
+
* An un-kept command is not in context, so showing it in the transcript would
|
|
59
|
+
* claim the agent can see something it cannot.
|
|
60
|
+
*/
|
|
61
|
+
export function transcriptTurns(turns) {
|
|
62
|
+
return turns.filter((t) => t.included || !readCommandTurn(t));
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=commandTurn.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commandTurn.js","sourceRoot":"","sources":["../commandTurn.ts"],"names":[],"mappings":"AAWA,oFAAoF;AACpF,MAAM,CAAC,MAAM,YAAY,GAAG,iBAAiB,CAAC;AAgB9C;wCACwC;AACxC,MAAM,UAAU,GAAG,GAAG,CAAC;AAIvB;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAAC,IAAsB;IACpD,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAA+C,CAAC;IAC7E,MAAM,IAAI,GAAG,KAAK,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,CAAC;IACpC,IAAI,IAAI,EAAE,QAAQ,EAAE,IAAI,KAAK,YAAY;QAAE,OAAO,IAAI,CAAC;IAEvD,IAAI,OAAO,GAAG,EAAE,CAAC;IACjB,IAAI,EAAE,GAAG,IAAI,CAAC;IACd,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,IAAI,IAAI,CAAuC,CAAC;QAC/F,OAAO,GAAG,OAAO,IAAI,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/D,wEAAwE;QACxE,2EAA2E;QAC3E,EAAE,GAAG,IAAI,CAAC,EAAE,KAAK,KAAK,CAAC;IACzB,CAAC;IAAC,MAAM,CAAC,CAAC,mDAAmD,CAAC,CAAC;IAE/D,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAsC,CAAC;IACrE,MAAM,MAAM,GAAG,OAAO,MAAM,EAAE,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;IACzE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,KAAK,EAAE,OAAO,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;AAC9G,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,WAAW,CAAC,KAAyB;IACnD,KAAK,IAAI,CAAC,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3C,MAAM,IAAI,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QACvC,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,KAAK;YAAE,SAAS;QAClC,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;IACjC,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,KAAyB;IACvD,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC;AAChE,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ConversationTurn } from '@corenel/harness/conversation';
|
|
2
|
+
/**
|
|
3
|
+
* Everything the composer can recall, oldest first.
|
|
4
|
+
*
|
|
5
|
+
* CONSECUTIVE DUPLICATES COLLAPSE. Running the same command three times in a
|
|
6
|
+
* row is common, and three presses of Up that appear to do nothing reads as a
|
|
7
|
+
* broken key rather than as history.
|
|
8
|
+
*/
|
|
9
|
+
export declare function composerHistory(turns: ConversationTurn[]): string[];
|
|
10
|
+
//# sourceMappingURL=composerHistory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"composerHistory.d.ts","sourceRoot":"","sources":["../composerHistory.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAyBtE;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,gBAAgB,EAAE,GAAG,MAAM,EAAE,CAUnE"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { readCommandTurn } from './commandTurn';
|
|
2
|
+
/** The prefix that makes a line a command. Kept in step with the host's
|
|
3
|
+
* COMMAND_PREFIX by the test that round-trips a recorded command. */
|
|
4
|
+
const COMMAND_PREFIX = '>';
|
|
5
|
+
/** The text of a user message turn, or null if it is not one. */
|
|
6
|
+
function userText(turn) {
|
|
7
|
+
const first = turn.messages[0];
|
|
8
|
+
if (first?.role !== 'user')
|
|
9
|
+
return null;
|
|
10
|
+
if (typeof first.content === 'string')
|
|
11
|
+
return first.content;
|
|
12
|
+
// A multimodal turn is an array of parts; recall the text, since the images
|
|
13
|
+
// cannot be put back in the box anyway.
|
|
14
|
+
if (Array.isArray(first.content)) {
|
|
15
|
+
const text = first.content
|
|
16
|
+
.filter((p) => p?.type === 'text' && typeof p.text === 'string')
|
|
17
|
+
.map((p) => p.text)
|
|
18
|
+
.join('\n')
|
|
19
|
+
.trim();
|
|
20
|
+
return text || null;
|
|
21
|
+
}
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Everything the composer can recall, oldest first.
|
|
26
|
+
*
|
|
27
|
+
* CONSECUTIVE DUPLICATES COLLAPSE. Running the same command three times in a
|
|
28
|
+
* row is common, and three presses of Up that appear to do nothing reads as a
|
|
29
|
+
* broken key rather than as history.
|
|
30
|
+
*/
|
|
31
|
+
export function composerHistory(turns) {
|
|
32
|
+
const out = [];
|
|
33
|
+
for (const turn of turns) {
|
|
34
|
+
const cmd = readCommandTurn(turn);
|
|
35
|
+
const entry = cmd ? `${COMMAND_PREFIX}${cmd.command}` : userText(turn);
|
|
36
|
+
if (!entry)
|
|
37
|
+
continue;
|
|
38
|
+
if (out[out.length - 1] === entry)
|
|
39
|
+
continue;
|
|
40
|
+
out.push(entry);
|
|
41
|
+
}
|
|
42
|
+
return out;
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=composerHistory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"composerHistory.js","sourceRoot":"","sources":["../composerHistory.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAEhD;qEACqE;AACrE,MAAM,cAAc,GAAG,GAAG,CAAC;AAE3B,iEAAiE;AACjE,SAAS,QAAQ,CAAC,IAAsB;IACtC,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAqD,CAAC;IACnF,IAAI,KAAK,EAAE,IAAI,KAAK,MAAM;QAAE,OAAO,IAAI,CAAC;IACxC,IAAI,OAAO,KAAK,CAAC,OAAO,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC,OAAO,CAAC;IAC5D,4EAA4E;IAC5E,wCAAwC;IACxC,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;QACjC,MAAM,IAAI,GAAI,KAAK,CAAC,OAA8C;aAC/D,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,KAAK,MAAM,IAAI,OAAO,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC;aAC/D,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;aAClB,IAAI,CAAC,IAAI,CAAC;aACV,IAAI,EAAE,CAAC;QACV,OAAO,IAAI,IAAI,IAAI,CAAC;IACtB,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAAC,KAAyB;IACvD,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,GAAG,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;QAClC,MAAM,KAAK,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,cAAc,GAAG,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QACvE,IAAI,CAAC,KAAK;YAAE,SAAS;QACrB,IAAI,GAAG,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,KAAK;YAAE,SAAS;QAC5C,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAClB,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { type QueuedSend } from './queue';
|
|
3
|
+
/**
|
|
4
|
+
* Runs the queue: ticks, fires what is due, and re-renders on every change.
|
|
5
|
+
*
|
|
6
|
+
* `send` is called with the parked text and must send it exactly as a typed
|
|
7
|
+
* message would be sent. It is held in a ref so a fresh closure each render
|
|
8
|
+
* never restarts the interval.
|
|
9
|
+
*
|
|
10
|
+
* `busy` suppresses firing while a turn is running -- the message stays queued
|
|
11
|
+
* and goes on the next tick instead. Dropping it would lose what the user
|
|
12
|
+
* parked; sending into a running turn is not possible.
|
|
13
|
+
*/
|
|
14
|
+
export declare function useSendLater(send: (text: string) => void, busy: boolean): {
|
|
15
|
+
items: QueuedSend[];
|
|
16
|
+
now: number;
|
|
17
|
+
};
|
|
18
|
+
export interface SendLaterProps {
|
|
19
|
+
/** The composer's current text -- what gets parked. */
|
|
20
|
+
text: string;
|
|
21
|
+
/** Clears the composer after parking, so the message is in one place only. */
|
|
22
|
+
onQueued: () => void;
|
|
23
|
+
/** Sends a MISSED message the user chose to release. Same send path as the
|
|
24
|
+
* timer's -- the difference is only who decided. */
|
|
25
|
+
onSendNow: (text: string) => void;
|
|
26
|
+
/** The live queue + clock from useSendLater. */
|
|
27
|
+
items: QueuedSend[];
|
|
28
|
+
now: number;
|
|
29
|
+
}
|
|
30
|
+
export declare function SendLater({ text, onQueued, onSendNow, items, now }: SendLaterProps): React.ReactElement;
|
|
31
|
+
//# sourceMappingURL=SendLater.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SendLater.d.ts","sourceRoot":"","sources":["../../sendLater/SendLater.tsx"],"names":[],"mappings":"AAUA,OAAO,KAAmD,MAAM,OAAO,CAAC;AAExE,OAAO,EAGyB,KAAK,UAAU,EAC9C,MAAM,SAAS,CAAC;AAajB;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,EAAE,IAAI,EAAE,OAAO;;;EA4BvE;AAED,MAAM,WAAW,cAAc;IAC7B,uDAAuD;IACvD,IAAI,EAAE,MAAM,CAAC;IACb,8EAA8E;IAC9E,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB;wDACoD;IACpD,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,gDAAgD;IAChD,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,GAAG,EAAE,MAAM,CAAC;CACb;AAED,wBAAgB,SAAS,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,cAAc,GAAG,KAAK,CAAC,YAAY,CAoIvG"}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
/* The "send later" control, beside Send.
|
|
3
|
+
*
|
|
4
|
+
* A clock button that parks whatever is in the composer and a list of what is
|
|
5
|
+
* already parked, each editable and cancellable. See queue.ts for why this is
|
|
6
|
+
* explicitly not a scheduled task.
|
|
7
|
+
*
|
|
8
|
+
* The firing loop lives here too, in useSendLater, because a timer needs a
|
|
9
|
+
* component's lifetime to be cleaned up and this is the component that is
|
|
10
|
+
* mounted for exactly as long as the chat is.
|
|
11
|
+
*/
|
|
12
|
+
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
13
|
+
import { IcClock, IcX, IcCheck } from '@corenel/ui-kit/icons';
|
|
14
|
+
import { PRESETS, HOUR_OPTIONS, queued, queueSend, editQueued, cancelQueued, takeDue, takeOne, requeue, missDuringGap, onQueueChange, formatRemaining, remainingMs, } from './queue';
|
|
15
|
+
/** How often the queue is checked. A minute-resolution feature does not need a
|
|
16
|
+
* tighter loop, and the countdown only renders whole minutes. */
|
|
17
|
+
const TICK_MS = 5000;
|
|
18
|
+
/** A gap longer than this between ticks means the page was not really running --
|
|
19
|
+
* a slept machine, a throttled background tab. Anything that came due inside
|
|
20
|
+
* such a gap is MISSED, not sent, the same as if the tab had been closed:
|
|
21
|
+
* nobody was watching, so nothing sends itself. Generous next to TICK_MS so
|
|
22
|
+
* ordinary scheduler jitter never trips it. */
|
|
23
|
+
const UNWATCHED_GAP_MS = 90000;
|
|
24
|
+
/**
|
|
25
|
+
* Runs the queue: ticks, fires what is due, and re-renders on every change.
|
|
26
|
+
*
|
|
27
|
+
* `send` is called with the parked text and must send it exactly as a typed
|
|
28
|
+
* message would be sent. It is held in a ref so a fresh closure each render
|
|
29
|
+
* never restarts the interval.
|
|
30
|
+
*
|
|
31
|
+
* `busy` suppresses firing while a turn is running -- the message stays queued
|
|
32
|
+
* and goes on the next tick instead. Dropping it would lose what the user
|
|
33
|
+
* parked; sending into a running turn is not possible.
|
|
34
|
+
*/
|
|
35
|
+
export function useSendLater(send, busy) {
|
|
36
|
+
const [items, setItems] = useState(() => queued());
|
|
37
|
+
const [now, setNow] = useState(() => Date.now());
|
|
38
|
+
const sendRef = useRef(send);
|
|
39
|
+
sendRef.current = send;
|
|
40
|
+
const busyRef = useRef(busy);
|
|
41
|
+
busyRef.current = busy;
|
|
42
|
+
useEffect(() => onQueueChange(() => setItems(queued())), []);
|
|
43
|
+
const lastTick = useRef(Date.now());
|
|
44
|
+
useEffect(() => {
|
|
45
|
+
const tick = () => {
|
|
46
|
+
const t = Date.now();
|
|
47
|
+
const gap = t - lastTick.current;
|
|
48
|
+
lastTick.current = t;
|
|
49
|
+
setNow(t);
|
|
50
|
+
// Nothing was watching across that gap, so nothing sends itself.
|
|
51
|
+
if (gap > UNWATCHED_GAP_MS) {
|
|
52
|
+
missDuringGap(t);
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
if (busyRef.current)
|
|
56
|
+
return;
|
|
57
|
+
for (const due of takeDue(t))
|
|
58
|
+
sendRef.current(due.text);
|
|
59
|
+
};
|
|
60
|
+
tick();
|
|
61
|
+
const id = setInterval(tick, TICK_MS);
|
|
62
|
+
return () => clearInterval(id);
|
|
63
|
+
}, []);
|
|
64
|
+
return { items, now };
|
|
65
|
+
}
|
|
66
|
+
export function SendLater({ text, onQueued, onSendNow, items, now }) {
|
|
67
|
+
const [open, setOpen] = useState(false);
|
|
68
|
+
const [editing, setEditing] = useState(null);
|
|
69
|
+
const [draft, setDraft] = useState('');
|
|
70
|
+
const [hours, setHours] = useState(HOUR_OPTIONS[0]);
|
|
71
|
+
const wrapRef = useRef(null);
|
|
72
|
+
const canQueue = text.trim().length > 0;
|
|
73
|
+
useEffect(() => {
|
|
74
|
+
if (!open)
|
|
75
|
+
return;
|
|
76
|
+
const onDown = (e) => {
|
|
77
|
+
if (!wrapRef.current?.contains(e.target)) {
|
|
78
|
+
setOpen(false);
|
|
79
|
+
setEditing(null);
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
document.addEventListener('mousedown', onDown, true);
|
|
83
|
+
return () => document.removeEventListener('mousedown', onDown, true);
|
|
84
|
+
}, [open]);
|
|
85
|
+
const park = useCallback((minutes) => {
|
|
86
|
+
if (queueSend(text, minutes, Date.now())) {
|
|
87
|
+
onQueued();
|
|
88
|
+
setOpen(false);
|
|
89
|
+
}
|
|
90
|
+
}, [text, onQueued]);
|
|
91
|
+
const commitEdit = (id) => { editQueued(id, { text: draft }); setEditing(null); };
|
|
92
|
+
/* A missed message goes only when the user says so. takeOne removes before
|
|
93
|
+
* sending, like the timer path, so a double click cannot double send. */
|
|
94
|
+
const sendNow = (id) => { const e = takeOne(id); if (e)
|
|
95
|
+
onSendNow(e.text); };
|
|
96
|
+
const missedCount = items.filter((i) => i.missed).length;
|
|
97
|
+
const label = items.length ? String(items.length) : '';
|
|
98
|
+
return (_jsxs("div", { ref: wrapRef, style: S.wrap, children: [_jsxs("button", { style: { ...S.btn, ...(missedCount ? S.btnMissed : items.length ? S.btnActive : null) }, onClick: () => setOpen((o) => !o), title: missedCount
|
|
99
|
+
? `${missedCount} missed message${missedCount === 1 ? '' : 's'} waiting for you`
|
|
100
|
+
: items.length
|
|
101
|
+
? `${items.length} message${items.length === 1 ? '' : 's'} queued to send later`
|
|
102
|
+
: 'Send later', "aria-label": "Send later", children: [_jsx(IcClock, { size: 12 }), label && _jsx("span", { style: S.count, children: label })] }), open && (_jsxs("div", { style: S.menu, "data-dock-keepalive": true, children: [_jsx("div", { style: S.head, children: "Send later" }), canQueue ? (_jsxs(_Fragment, { children: [_jsx("div", { style: S.presets, children: PRESETS.map((p) => (_jsx("button", { style: S.preset, onClick: () => park(p.minutes), children: p.label }, p.label))) }), _jsxs("div", { style: S.hourRow, children: [_jsx("select", { style: S.select, value: hours, onChange: (e) => setHours(Number(e.target.value)), "aria-label": "Hours to wait", children: HOUR_OPTIONS.map((h) => _jsxs("option", { value: h, children: [h, " hours"] }, h)) }), _jsx("button", { style: S.hourGo, onClick: () => park(hours * 60), children: "Queue" })] })] })) : (_jsx("div", { style: S.empty, children: "Type a message first \u2014 this parks what is in the composer." })), items.length > 0 && (_jsxs(_Fragment, { children: [_jsx("div", { style: S.divider }), _jsx("div", { style: S.listHead, children: "Queued" }), _jsx("div", { style: S.list, children: items.map((it) => (_jsx("div", { style: S.item, children: editing === it.id ? (_jsxs(_Fragment, { children: [_jsx("textarea", { style: S.editBox, value: draft, autoFocus: true, onChange: (e) => setDraft(e.target.value), onKeyDown: (e) => {
|
|
103
|
+
if (e.key === 'Enter' && !e.shiftKey) {
|
|
104
|
+
e.preventDefault();
|
|
105
|
+
commitEdit(it.id);
|
|
106
|
+
}
|
|
107
|
+
if (e.key === 'Escape') {
|
|
108
|
+
e.preventDefault();
|
|
109
|
+
setEditing(null);
|
|
110
|
+
}
|
|
111
|
+
}, "aria-label": "Edit queued message" }), _jsx("button", { style: S.iconBtn, onClick: () => commitEdit(it.id), title: "Save", "aria-label": "Save", children: _jsx(IcCheck, { size: 12 }) })] })) : (_jsxs(_Fragment, { children: [_jsx("button", { style: S.itemText, title: it.text, onClick: () => { setEditing(it.id); setDraft(it.text); }, children: it.text }), it.missed ? (_jsxs(_Fragment, { children: [_jsx("span", { style: S.missedTag, children: "missed" }), _jsx("button", { style: S.sendNow, onClick: () => sendNow(it.id), title: "Send this now", "aria-label": "Send missed message now", children: "Send" }), _jsx("button", { style: S.iconBtn, onClick: () => requeue(it.id, 30, Date.now()), title: "Wait another 30m", "aria-label": "Re-queue for 30 minutes", children: _jsx(IcClock, { size: 12 }) })] })) : (_jsx("span", { style: S.due, children: formatRemaining(remainingMs(it, now)) })), _jsx("button", { style: S.iconBtn, onClick: () => cancelQueued(it.id), title: "Cancel", "aria-label": "Cancel queued message", children: _jsx(IcX, { size: 12 }) })] })) }, it.id))) }), _jsx("div", { style: S.note, children: missedCount > 0
|
|
112
|
+
? 'A missed message came due while this tab was closed or asleep. It waits for you rather than sending on its own.'
|
|
113
|
+
: 'Sends from this browser tab while it is open.' })] }))] }))] }));
|
|
114
|
+
}
|
|
115
|
+
const S = {
|
|
116
|
+
wrap: { position: 'relative', display: 'inline-flex' },
|
|
117
|
+
// 34px, matching the stance+Send control beside it -- the two controls sit on
|
|
118
|
+
// the same row and a shorter button reads as an afterthought.
|
|
119
|
+
btn: { display: 'inline-flex', alignItems: 'center', gap: 6, height: 34, padding: '0 12px', border: '1px solid var(--border-default)', borderRadius: 'var(--radius-sm)', background: 'var(--surface-2)', color: 'var(--text-secondary)', fontSize: 12.5, fontWeight: 600, fontFamily: 'inherit', boxShadow: 'var(--shadow-1)', cursor: 'pointer' },
|
|
120
|
+
// Full `border`, not `borderColor`: React warns (correctly) that removing a
|
|
121
|
+
// longhand on rerender while a shorthand is set leads to real styling bugs.
|
|
122
|
+
btnActive: { color: 'var(--accent)', border: '1px solid var(--accent)' },
|
|
123
|
+
btnMissed: { color: 'var(--warn, var(--accent))', border: '1px solid var(--warn, var(--accent))' },
|
|
124
|
+
missedTag: { flex: '0 0 auto', fontSize: 'var(--fs-caption, 11px)', fontWeight: 700, letterSpacing: '0.02em', color: 'var(--warn, var(--accent))' },
|
|
125
|
+
sendNow: { flex: '0 0 auto', height: 22, padding: '0 8px', border: '1px solid var(--border-default)', borderRadius: 'var(--radius-sm)', background: 'var(--surface-2)', color: 'var(--text-secondary)', fontSize: 'var(--fs-caption, 11px)', fontWeight: 700, cursor: 'pointer' },
|
|
126
|
+
count: { fontSize: 12.5, fontWeight: 700, fontVariantNumeric: 'tabular-nums' },
|
|
127
|
+
menu: { position: 'absolute', bottom: 'calc(100% + 6px)', left: 0, zIndex: 'var(--z-dropdown)', width: 300, padding: 8, background: 'var(--surface-1)', border: '1px solid var(--border-default)', borderRadius: 'var(--radius-md)', boxShadow: 'var(--shadow-4, 0 12px 32px rgba(0,0,0,0.4))' },
|
|
128
|
+
head: { fontSize: 'var(--fs-caption, 11px)', fontWeight: 700, letterSpacing: '0.04em', textTransform: 'uppercase', color: 'var(--text-tertiary)', padding: '2px 4px 6px' },
|
|
129
|
+
presets: { display: 'flex', gap: 4 },
|
|
130
|
+
preset: { flex: 1, height: 30, border: '1px solid var(--border-default)', borderRadius: 'var(--radius-sm)', background: 'var(--surface-2)', color: 'var(--text-secondary)', fontWeight: 600, cursor: 'pointer' },
|
|
131
|
+
hourRow: { display: 'flex', gap: 4, marginTop: 6 },
|
|
132
|
+
select: { flex: 1, height: 30, border: '1px solid var(--border-default)', borderRadius: 'var(--radius-sm)', background: 'var(--surface-2)', color: 'var(--text-secondary)', padding: '0 6px' },
|
|
133
|
+
hourGo: { height: 30, padding: '0 10px', border: '1px solid var(--border-default)', borderRadius: 'var(--radius-sm)', background: 'var(--surface-2)', color: 'var(--text-secondary)', fontWeight: 600, cursor: 'pointer' },
|
|
134
|
+
empty: { padding: '4px 4px 2px', color: 'var(--text-tertiary)', fontSize: 'var(--fs-body-sm)' },
|
|
135
|
+
divider: { height: 1, margin: '8px 0', background: 'var(--border-default)' },
|
|
136
|
+
listHead: { fontSize: 'var(--fs-caption, 11px)', fontWeight: 700, letterSpacing: '0.04em', textTransform: 'uppercase', color: 'var(--text-tertiary)', padding: '0 4px 4px' },
|
|
137
|
+
list: { display: 'flex', flexDirection: 'column', gap: 2, maxHeight: 180, overflow: 'auto' },
|
|
138
|
+
item: { display: 'flex', alignItems: 'center', gap: 4, padding: '2px 2px 2px 4px', borderRadius: 'var(--radius-sm)' },
|
|
139
|
+
itemText: { flex: 1, minWidth: 0, border: 'none', background: 'none', padding: 0, color: 'var(--text-secondary)', font: 'inherit', fontSize: 'var(--fs-body-sm)', textAlign: 'left', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', cursor: 'text' },
|
|
140
|
+
editBox: { flex: 1, minWidth: 0, minHeight: 52, resize: 'vertical', border: '1px solid var(--border-default)', borderRadius: 'var(--radius-sm)', background: 'var(--surface-2)', color: 'var(--text-primary)', font: 'inherit', fontSize: 'var(--fs-body-sm)', padding: 4 },
|
|
141
|
+
due: { flex: '0 0 auto', fontSize: 'var(--fs-caption, 11px)', color: 'var(--text-tertiary)', fontVariantNumeric: 'tabular-nums' },
|
|
142
|
+
iconBtn: { flex: '0 0 auto', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', width: 22, height: 22, border: 'none', background: 'none', color: 'var(--text-tertiary)', cursor: 'pointer' },
|
|
143
|
+
note: { padding: '6px 4px 0', color: 'var(--text-tertiary)', fontSize: 'var(--fs-caption, 11px)', lineHeight: 1.4 },
|
|
144
|
+
};
|
|
145
|
+
//# sourceMappingURL=SendLater.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SendLater.js","sourceRoot":"","sources":["../../sendLater/SendLater.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/** One parked message. */
|
|
2
|
+
export interface QueuedSend {
|
|
3
|
+
id: string;
|
|
4
|
+
/** Exactly what will be sent -- the composer's text at queue time, editable after. */
|
|
5
|
+
text: string;
|
|
6
|
+
/** Epoch ms when it should go. */
|
|
7
|
+
dueAt: number;
|
|
8
|
+
/** Epoch ms when it was queued, for "in 20m" vs "queued 20m ago" in the UI. */
|
|
9
|
+
createdAt: number;
|
|
10
|
+
/** Its moment passed while nothing was watching (tab closed, machine asleep).
|
|
11
|
+
* Held rather than sent; the user decides. */
|
|
12
|
+
missed?: boolean;
|
|
13
|
+
}
|
|
14
|
+
/** Presets, in minutes. The dropdown adds longer waits in whole hours. */
|
|
15
|
+
export declare const PRESETS: {
|
|
16
|
+
label: string;
|
|
17
|
+
minutes: number;
|
|
18
|
+
}[];
|
|
19
|
+
/** Longer waits offered in the dropdown, in hours. */
|
|
20
|
+
export declare const HOUR_OPTIONS: number[];
|
|
21
|
+
type Listener = () => void;
|
|
22
|
+
/** Subscribe to queue changes. Returns an unsubscribe. */
|
|
23
|
+
export declare function onQueueChange(l: Listener): () => void;
|
|
24
|
+
/** Everything parked, soonest first. */
|
|
25
|
+
export declare function queued(): QueuedSend[];
|
|
26
|
+
/** Park `text` to be sent in `minutes`. Returns the new entry. */
|
|
27
|
+
export declare function queueSend(text: string, minutes: number, now: number): QueuedSend | null;
|
|
28
|
+
/** Change a parked message's text and/or when it goes. */
|
|
29
|
+
export declare function editQueued(id: string, patch: {
|
|
30
|
+
text?: string;
|
|
31
|
+
dueAt?: number;
|
|
32
|
+
}): void;
|
|
33
|
+
/** Drop a parked message. */
|
|
34
|
+
export declare function cancelQueued(id: string): void;
|
|
35
|
+
/** Drop everything (used by tests and a "clear all" affordance). */
|
|
36
|
+
export declare function clearQueue(): void;
|
|
37
|
+
/**
|
|
38
|
+
* Take everything due at `now` off the queue and return it, soonest first.
|
|
39
|
+
*
|
|
40
|
+
* Removing before sending is deliberate: a message that fires must not be able
|
|
41
|
+
* to fire twice if the send throws, because the user asked for it to be sent
|
|
42
|
+
* once. A failed send surfaces in the transcript like any other failed send.
|
|
43
|
+
*/
|
|
44
|
+
export declare function takeDue(now: number): QueuedSend[];
|
|
45
|
+
/**
|
|
46
|
+
* Mark everything that became due during a gap as missed, and return how many.
|
|
47
|
+
*
|
|
48
|
+
* The tab being closed is not the only way a moment passes unwatched -- a
|
|
49
|
+
* sleeping laptop leaves the interval un-run for hours with the page still
|
|
50
|
+
* mounted. Both are the same thing to the person who parked the message, so
|
|
51
|
+
* both get the same answer.
|
|
52
|
+
*/
|
|
53
|
+
export declare function missDuringGap(now: number): number;
|
|
54
|
+
/** Take one entry off the queue by id and return it -- the "send it now" path
|
|
55
|
+
* for a missed message. Removed before sending, like takeDue, so one click
|
|
56
|
+
* cannot become two sends. */
|
|
57
|
+
export declare function takeOne(id: string): QueuedSend | null;
|
|
58
|
+
/** Re-arm a missed message for `minutes` from now. */
|
|
59
|
+
export declare function requeue(id: string, minutes: number, now: number): void;
|
|
60
|
+
/** ms until this entry is due; <= 0 means overdue. */
|
|
61
|
+
export declare function remainingMs(entry: QueuedSend, now: number): number;
|
|
62
|
+
/** "5m", "1h 20m", "now" — the countdown shown on a parked message. */
|
|
63
|
+
export declare function formatRemaining(ms: number): string;
|
|
64
|
+
/** Test hook: reset module state so each test starts empty. */
|
|
65
|
+
export declare function resetQueueForTest(): void;
|
|
66
|
+
/** Test hook: reload from storage (proves persistence across a "reload"). */
|
|
67
|
+
export declare function reloadQueueForTest(): void;
|
|
68
|
+
export {};
|
|
69
|
+
//# sourceMappingURL=queue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queue.d.ts","sourceRoot":"","sources":["../../sendLater/queue.ts"],"names":[],"mappings":"AAmBA,0BAA0B;AAC1B,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,sFAAsF;IACtF,IAAI,EAAE,MAAM,CAAC;IACb,kCAAkC;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,+EAA+E;IAC/E,SAAS,EAAE,MAAM,CAAC;IAClB;kDAC8C;IAC9C,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAID,0EAA0E;AAC1E,eAAO,MAAM,OAAO,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,EAMvD,CAAC;AAEF,sDAAsD;AACtD,eAAO,MAAM,YAAY,UAA6B,CAAC;AAEvD,KAAK,QAAQ,GAAG,MAAM,IAAI,CAAC;AAmC3B,0DAA0D;AAC1D,wBAAgB,aAAa,CAAC,CAAC,EAAE,QAAQ,GAAG,MAAM,IAAI,CAGrD;AAED,wCAAwC;AACxC,wBAAgB,MAAM,IAAI,UAAU,EAAE,CAErC;AAED,kEAAkE;AAClE,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAcvF;AAED,0DAA0D;AAC1D,wBAAgB,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAerF;AAED,6BAA6B;AAC7B,wBAAgB,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAG7C;AAED,oEAAoE;AACpE,wBAAgB,UAAU,IAAI,IAAI,CAEjC;AAED;;;;;;GAMG;AACH,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,EAAE,CAOjD;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CASjD;AAED;;+BAE+B;AAC/B,wBAAgB,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAIrD;AAED,sDAAsD;AACtD,wBAAgB,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAStE;AAED,sDAAsD;AACtD,wBAAgB,WAAW,CAAC,KAAK,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAElE;AAED,uEAAuE;AACvE,wBAAgB,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAOlD;AAED,+DAA+D;AAC/D,wBAAgB,iBAAiB,IAAI,IAAI,CAIxC;AAED,6EAA6E;AAC7E,wBAAgB,kBAAkB,IAAI,IAAI,CAEzC"}
|