@askexenow/exe-os 0.9.8 → 0.9.9
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/bin/backfill-conversations.js +222 -49
- package/dist/bin/backfill-responses.js +221 -48
- package/dist/bin/backfill-vectors.js +225 -52
- package/dist/bin/cleanup-stale-review-tasks.js +150 -28
- package/dist/bin/cli.js +1295 -856
- package/dist/bin/exe-agent-config.js +36 -8
- package/dist/bin/exe-agent.js +14 -4
- package/dist/bin/exe-assign.js +221 -48
- package/dist/bin/exe-boot.js +778 -427
- package/dist/bin/exe-call.js +41 -13
- package/dist/bin/exe-cloud.js +163 -58
- package/dist/bin/exe-dispatch.js +276 -139
- package/dist/bin/exe-doctor.js +145 -27
- package/dist/bin/exe-export-behaviors.js +141 -23
- package/dist/bin/exe-forget.js +137 -19
- package/dist/bin/exe-gateway.js +677 -388
- package/dist/bin/exe-heartbeat.js +227 -108
- package/dist/bin/exe-kill.js +138 -20
- package/dist/bin/exe-launch-agent.js +172 -39
- package/dist/bin/exe-link.js +291 -100
- package/dist/bin/exe-new-employee.js +214 -106
- package/dist/bin/exe-pending-messages.js +395 -33
- package/dist/bin/exe-pending-notifications.js +684 -99
- package/dist/bin/exe-pending-reviews.js +420 -74
- package/dist/bin/exe-rename.js +147 -49
- package/dist/bin/exe-review.js +138 -20
- package/dist/bin/exe-search.js +240 -69
- package/dist/bin/exe-session-cleanup.js +440 -250
- package/dist/bin/exe-settings.js +61 -17
- package/dist/bin/exe-start-codex.js +158 -39
- package/dist/bin/exe-start-opencode.js +157 -38
- package/dist/bin/exe-status.js +151 -29
- package/dist/bin/exe-team.js +138 -20
- package/dist/bin/git-sweep.js +404 -212
- package/dist/bin/graph-backfill.js +137 -19
- package/dist/bin/graph-export.js +140 -22
- package/dist/bin/install.js +90 -61
- package/dist/bin/scan-tasks.js +412 -220
- package/dist/bin/setup.js +564 -293
- package/dist/bin/shard-migrate.js +139 -21
- package/dist/bin/update.js +138 -49
- package/dist/bin/wiki-sync.js +137 -19
- package/dist/gateway/index.js +533 -320
- package/dist/hooks/bug-report-worker.js +344 -193
- package/dist/hooks/codex-stop-task-finalizer.js +4678 -0
- package/dist/hooks/commit-complete.js +402 -210
- package/dist/hooks/error-recall.js +245 -74
- package/dist/hooks/exe-heartbeat-hook.js +16 -6
- package/dist/hooks/ingest-worker.js +3423 -3157
- package/dist/hooks/ingest.js +832 -97
- package/dist/hooks/instructions-loaded.js +227 -54
- package/dist/hooks/notification.js +216 -43
- package/dist/hooks/post-compact.js +239 -62
- package/dist/hooks/pre-compact.js +408 -216
- package/dist/hooks/pre-tool-use.js +268 -90
- package/dist/hooks/prompt-ingest-worker.js +352 -102
- package/dist/hooks/prompt-submit.js +541 -328
- package/dist/hooks/response-ingest-worker.js +372 -122
- package/dist/hooks/session-end.js +443 -240
- package/dist/hooks/session-start.js +313 -127
- package/dist/hooks/stop.js +293 -98
- package/dist/hooks/subagent-stop.js +239 -62
- package/dist/hooks/summary-worker.js +568 -236
- package/dist/index.js +538 -324
- package/dist/lib/agent-config.js +28 -6
- package/dist/lib/cloud-sync.js +284 -105
- package/dist/lib/config.js +30 -10
- package/dist/lib/consolidation.js +16 -6
- package/dist/lib/database.js +123 -25
- package/dist/lib/db-daemon-client.js +73 -19
- package/dist/lib/db.js +123 -25
- package/dist/lib/device-registry.js +133 -35
- package/dist/lib/embedder.js +107 -32
- package/dist/lib/employee-templates.js +14 -4
- package/dist/lib/employees.js +41 -13
- package/dist/lib/exe-daemon-client.js +88 -22
- package/dist/lib/exe-daemon.js +935 -587
- package/dist/lib/hybrid-search.js +240 -69
- package/dist/lib/identity.js +18 -8
- package/dist/lib/license.js +133 -48
- package/dist/lib/messaging.js +116 -56
- package/dist/lib/reminders.js +14 -4
- package/dist/lib/schedules.js +137 -19
- package/dist/lib/skill-learning.js +33 -6
- package/dist/lib/store.js +137 -19
- package/dist/lib/task-router.js +14 -4
- package/dist/lib/tasks.js +280 -234
- package/dist/lib/tmux-routing.js +172 -125
- package/dist/lib/token-spend.js +26 -8
- package/dist/mcp/server.js +1326 -609
- package/dist/mcp/tools/complete-reminder.js +14 -4
- package/dist/mcp/tools/create-reminder.js +14 -4
- package/dist/mcp/tools/create-task.js +306 -248
- package/dist/mcp/tools/deactivate-behavior.js +16 -6
- package/dist/mcp/tools/list-reminders.js +14 -4
- package/dist/mcp/tools/list-tasks.js +123 -107
- package/dist/mcp/tools/send-message.js +75 -29
- package/dist/mcp/tools/update-task.js +1848 -199
- package/dist/runtime/index.js +441 -248
- package/dist/tui/App.js +761 -424
- package/package.json +1 -1
|
@@ -26,9 +26,18 @@ var init_db_retry = __esm({
|
|
|
26
26
|
}
|
|
27
27
|
});
|
|
28
28
|
|
|
29
|
+
// src/lib/secure-files.ts
|
|
30
|
+
import { chmodSync, existsSync, mkdirSync } from "fs";
|
|
31
|
+
import { chmod, mkdir } from "fs/promises";
|
|
32
|
+
var init_secure_files = __esm({
|
|
33
|
+
"src/lib/secure-files.ts"() {
|
|
34
|
+
"use strict";
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
|
|
29
38
|
// src/lib/config.ts
|
|
30
|
-
import { readFile, writeFile
|
|
31
|
-
import { readFileSync, existsSync, renameSync } from "fs";
|
|
39
|
+
import { readFile, writeFile } from "fs/promises";
|
|
40
|
+
import { readFileSync, existsSync as existsSync2, renameSync } from "fs";
|
|
32
41
|
import path from "path";
|
|
33
42
|
import os from "os";
|
|
34
43
|
function resolveDataDir() {
|
|
@@ -36,7 +45,7 @@ function resolveDataDir() {
|
|
|
36
45
|
if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
|
|
37
46
|
const newDir = path.join(os.homedir(), ".exe-os");
|
|
38
47
|
const legacyDir = path.join(os.homedir(), ".exe-mem");
|
|
39
|
-
if (!
|
|
48
|
+
if (!existsSync2(newDir) && existsSync2(legacyDir)) {
|
|
40
49
|
try {
|
|
41
50
|
renameSync(legacyDir, newDir);
|
|
42
51
|
process.stderr.write(`[exe-os] Migrated data directory: ~/.exe-mem \u2192 ~/.exe-os
|
|
@@ -51,6 +60,7 @@ var EXE_AI_DIR, DB_PATH, MODELS_DIR, CONFIG_PATH, LEGACY_LANCE_PATH, CURRENT_CON
|
|
|
51
60
|
var init_config = __esm({
|
|
52
61
|
"src/lib/config.ts"() {
|
|
53
62
|
"use strict";
|
|
63
|
+
init_secure_files();
|
|
54
64
|
EXE_AI_DIR = resolveDataDir();
|
|
55
65
|
DB_PATH = path.join(EXE_AI_DIR, "memories.db");
|
|
56
66
|
MODELS_DIR = path.join(EXE_AI_DIR, "models");
|
|
@@ -119,7 +129,7 @@ var init_config = __esm({
|
|
|
119
129
|
|
|
120
130
|
// src/lib/employees.ts
|
|
121
131
|
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
122
|
-
import { existsSync as
|
|
132
|
+
import { existsSync as existsSync3, symlinkSync, readlinkSync, readFileSync as readFileSync2, renameSync as renameSync2, unlinkSync, writeFileSync } from "fs";
|
|
123
133
|
import { execSync } from "child_process";
|
|
124
134
|
import path2 from "path";
|
|
125
135
|
import os2 from "os";
|
|
@@ -136,7 +146,7 @@ function getCoordinatorName(employees = loadEmployeesSync()) {
|
|
|
136
146
|
return getCoordinatorEmployee(employees)?.name ?? DEFAULT_COORDINATOR_TEMPLATE_NAME;
|
|
137
147
|
}
|
|
138
148
|
function loadEmployeesSync(employeesPath = EMPLOYEES_PATH) {
|
|
139
|
-
if (!
|
|
149
|
+
if (!existsSync3(employeesPath)) return [];
|
|
140
150
|
try {
|
|
141
151
|
return JSON.parse(readFileSync2(employeesPath, "utf-8"));
|
|
142
152
|
} catch {
|
|
@@ -460,10 +470,10 @@ var init_runtime_table = __esm({
|
|
|
460
470
|
});
|
|
461
471
|
|
|
462
472
|
// src/lib/agent-config.ts
|
|
463
|
-
import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, existsSync as
|
|
473
|
+
import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, existsSync as existsSync4 } from "fs";
|
|
464
474
|
import path5 from "path";
|
|
465
475
|
function loadAgentConfig() {
|
|
466
|
-
if (!
|
|
476
|
+
if (!existsSync4(AGENT_CONFIG_PATH)) return {};
|
|
467
477
|
try {
|
|
468
478
|
return JSON.parse(readFileSync3(AGENT_CONFIG_PATH, "utf-8"));
|
|
469
479
|
} catch {
|
|
@@ -484,6 +494,7 @@ var init_agent_config = __esm({
|
|
|
484
494
|
"use strict";
|
|
485
495
|
init_config();
|
|
486
496
|
init_runtime_table();
|
|
497
|
+
init_secure_files();
|
|
487
498
|
AGENT_CONFIG_PATH = path5.join(EXE_AI_DIR, "agent-config.json");
|
|
488
499
|
DEFAULT_MODELS = {
|
|
489
500
|
claude: "claude-opus-4",
|
|
@@ -494,16 +505,16 @@ var init_agent_config = __esm({
|
|
|
494
505
|
});
|
|
495
506
|
|
|
496
507
|
// src/lib/intercom-queue.ts
|
|
497
|
-
import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, renameSync as renameSync3, existsSync as
|
|
508
|
+
import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, renameSync as renameSync3, existsSync as existsSync5, mkdirSync as mkdirSync2 } from "fs";
|
|
498
509
|
import path6 from "path";
|
|
499
510
|
import os5 from "os";
|
|
500
511
|
function ensureDir() {
|
|
501
512
|
const dir = path6.dirname(QUEUE_PATH);
|
|
502
|
-
if (!
|
|
513
|
+
if (!existsSync5(dir)) mkdirSync2(dir, { recursive: true });
|
|
503
514
|
}
|
|
504
515
|
function readQueue() {
|
|
505
516
|
try {
|
|
506
|
-
if (!
|
|
517
|
+
if (!existsSync5(QUEUE_PATH)) return [];
|
|
507
518
|
return JSON.parse(readFileSync4(QUEUE_PATH, "utf8"));
|
|
508
519
|
} catch {
|
|
509
520
|
return [];
|
|
@@ -543,8 +554,11 @@ var init_intercom_queue = __esm({
|
|
|
543
554
|
});
|
|
544
555
|
|
|
545
556
|
// src/lib/license.ts
|
|
546
|
-
import { readFileSync as readFileSync5, writeFileSync as writeFileSync4, existsSync as
|
|
557
|
+
import { readFileSync as readFileSync5, writeFileSync as writeFileSync4, existsSync as existsSync6, mkdirSync as mkdirSync3 } from "fs";
|
|
547
558
|
import { randomUUID } from "crypto";
|
|
559
|
+
import { createRequire as createRequire2 } from "module";
|
|
560
|
+
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
561
|
+
import os6 from "os";
|
|
548
562
|
import path7 from "path";
|
|
549
563
|
import { jwtVerify, importSPKI } from "jose";
|
|
550
564
|
var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH;
|
|
@@ -559,7 +573,7 @@ var init_license = __esm({
|
|
|
559
573
|
});
|
|
560
574
|
|
|
561
575
|
// src/lib/plan-limits.ts
|
|
562
|
-
import { readFileSync as readFileSync6, existsSync as
|
|
576
|
+
import { readFileSync as readFileSync6, existsSync as existsSync7 } from "fs";
|
|
563
577
|
import path8 from "path";
|
|
564
578
|
var CACHE_PATH2;
|
|
565
579
|
var init_plan_limits = __esm({
|
|
@@ -575,9 +589,9 @@ var init_plan_limits = __esm({
|
|
|
575
589
|
|
|
576
590
|
// src/lib/tmux-routing.ts
|
|
577
591
|
import { execFileSync as execFileSync2, execSync as execSync4 } from "child_process";
|
|
578
|
-
import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, mkdirSync as mkdirSync4, existsSync as
|
|
592
|
+
import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, mkdirSync as mkdirSync4, existsSync as existsSync8, appendFileSync, readdirSync } from "fs";
|
|
579
593
|
import path9 from "path";
|
|
580
|
-
import
|
|
594
|
+
import os7 from "os";
|
|
581
595
|
import { fileURLToPath } from "url";
|
|
582
596
|
function getMySession() {
|
|
583
597
|
return getTransport().getMySession();
|
|
@@ -650,7 +664,7 @@ function isEmployeeAlive(sessionName) {
|
|
|
650
664
|
}
|
|
651
665
|
function readDebounceState() {
|
|
652
666
|
try {
|
|
653
|
-
if (!
|
|
667
|
+
if (!existsSync8(DEBOUNCE_FILE)) return {};
|
|
654
668
|
const raw = JSON.parse(readFileSync7(DEBOUNCE_FILE, "utf8"));
|
|
655
669
|
const state = {};
|
|
656
670
|
for (const [key, val] of Object.entries(raw)) {
|
|
@@ -667,7 +681,7 @@ function readDebounceState() {
|
|
|
667
681
|
}
|
|
668
682
|
function writeDebounceState(state) {
|
|
669
683
|
try {
|
|
670
|
-
if (!
|
|
684
|
+
if (!existsSync8(SESSION_CACHE)) mkdirSync4(SESSION_CACHE, { recursive: true });
|
|
671
685
|
writeFileSync5(DEBOUNCE_FILE, JSON.stringify(state));
|
|
672
686
|
} catch {
|
|
673
687
|
}
|
|
@@ -763,7 +777,7 @@ function sendIntercom(targetSession) {
|
|
|
763
777
|
const rawAgent = targetSession.split("-")[0] ?? targetSession;
|
|
764
778
|
const agent = baseAgentName(rawAgent);
|
|
765
779
|
const markerPath = path9.join(SESSION_CACHE, `current-task-${agent}.json`);
|
|
766
|
-
if (
|
|
780
|
+
if (existsSync8(markerPath)) {
|
|
767
781
|
logIntercom(`SKIP \u2192 ${targetSession} (has in_progress task marker \u2014 will auto-chain)`);
|
|
768
782
|
return "debounced";
|
|
769
783
|
}
|
|
@@ -773,7 +787,7 @@ function sendIntercom(targetSession) {
|
|
|
773
787
|
const rawAgent = targetSession.split("-")[0] ?? targetSession;
|
|
774
788
|
const agent = baseAgentName(rawAgent);
|
|
775
789
|
const taskDir = path9.join(process.cwd(), "exe", agent);
|
|
776
|
-
if (
|
|
790
|
+
if (existsSync8(taskDir)) {
|
|
777
791
|
const files = readdirSync(taskDir).filter(
|
|
778
792
|
(f) => f.endsWith(".md") && f !== "DONE.txt"
|
|
779
793
|
);
|
|
@@ -826,24 +840,49 @@ var init_tmux_routing = __esm({
|
|
|
826
840
|
init_intercom_queue();
|
|
827
841
|
init_plan_limits();
|
|
828
842
|
init_employees();
|
|
829
|
-
SPAWN_LOCK_DIR = path9.join(
|
|
830
|
-
SESSION_CACHE = path9.join(
|
|
843
|
+
SPAWN_LOCK_DIR = path9.join(os7.homedir(), ".exe-os", "spawn-locks");
|
|
844
|
+
SESSION_CACHE = path9.join(os7.homedir(), ".exe-os", "session-cache");
|
|
831
845
|
VALID_SESSION_NAME = /^[a-z]+\d*-[a-zA-Z0-9_]+$/;
|
|
832
846
|
INTERCOM_DEBOUNCE_MS = 3e4;
|
|
833
847
|
CODEX_DEBOUNCE_MS = 12e4;
|
|
834
|
-
INTERCOM_LOG2 = path9.join(
|
|
848
|
+
INTERCOM_LOG2 = path9.join(os7.homedir(), ".exe-os", "intercom.log");
|
|
835
849
|
DEBOUNCE_FILE = path9.join(SESSION_CACHE, "intercom-debounce.json");
|
|
836
850
|
DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
|
|
837
851
|
BUSY_PATTERN = /[✻✽✶✳·].*…|Running…|• Working|• Ran |• Explored|• Called|esc to interrupt/;
|
|
838
852
|
}
|
|
839
853
|
});
|
|
840
854
|
|
|
855
|
+
// src/lib/task-scope.ts
|
|
856
|
+
function getCurrentSessionScope() {
|
|
857
|
+
try {
|
|
858
|
+
return resolveExeSession();
|
|
859
|
+
} catch {
|
|
860
|
+
return null;
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
function strictSessionScopeFilter(sessionScope, tableAlias) {
|
|
864
|
+
const scope = sessionScope !== void 0 ? sessionScope : getCurrentSessionScope();
|
|
865
|
+
if (!scope) return { sql: "", args: [] };
|
|
866
|
+
const col = tableAlias ? `${tableAlias}.session_scope` : "session_scope";
|
|
867
|
+
return {
|
|
868
|
+
sql: ` AND ${col} = ?`,
|
|
869
|
+
args: [scope]
|
|
870
|
+
};
|
|
871
|
+
}
|
|
872
|
+
var init_task_scope = __esm({
|
|
873
|
+
"src/lib/task-scope.ts"() {
|
|
874
|
+
"use strict";
|
|
875
|
+
init_tmux_routing();
|
|
876
|
+
}
|
|
877
|
+
});
|
|
878
|
+
|
|
841
879
|
// src/mcp/tools/send-message.ts
|
|
842
880
|
import { z } from "zod";
|
|
843
881
|
|
|
844
882
|
// src/lib/messaging.ts
|
|
845
883
|
init_database();
|
|
846
884
|
init_tmux_routing();
|
|
885
|
+
init_task_scope();
|
|
847
886
|
import crypto from "crypto";
|
|
848
887
|
function generateUlid() {
|
|
849
888
|
const timestamp = Date.now().toString(36).padStart(10, "0");
|
|
@@ -858,6 +897,7 @@ function rowToMessage(row) {
|
|
|
858
897
|
targetAgent: row.target_agent,
|
|
859
898
|
targetProject: row.target_project ?? null,
|
|
860
899
|
targetDevice: row.target_device,
|
|
900
|
+
sessionScope: row.session_scope ?? null,
|
|
861
901
|
content: row.content,
|
|
862
902
|
priority: row.priority ?? "normal",
|
|
863
903
|
status: row.status ?? "pending",
|
|
@@ -876,15 +916,17 @@ async function sendMessage(input) {
|
|
|
876
916
|
const id = generateUlid();
|
|
877
917
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
878
918
|
const targetDevice = input.targetDevice ?? "local";
|
|
919
|
+
const sessionScope = input.sessionScope === void 0 ? resolveExeSession() : input.sessionScope;
|
|
879
920
|
await client.execute({
|
|
880
|
-
sql: `INSERT INTO messages (id, from_agent, from_device, target_agent, target_project, target_device, content, priority, status, created_at)
|
|
881
|
-
VALUES (?, ?, 'local', ?, ?, ?, ?, ?, 'pending', ?)`,
|
|
921
|
+
sql: `INSERT INTO messages (id, from_agent, from_device, target_agent, target_project, target_device, session_scope, content, priority, status, created_at)
|
|
922
|
+
VALUES (?, ?, 'local', ?, ?, ?, ?, ?, ?, 'pending', ?)`,
|
|
882
923
|
args: [
|
|
883
924
|
id,
|
|
884
925
|
input.fromAgent,
|
|
885
926
|
input.targetAgent,
|
|
886
927
|
input.targetProject ?? null,
|
|
887
928
|
targetDevice,
|
|
929
|
+
sessionScope,
|
|
888
930
|
input.content,
|
|
889
931
|
input.priority ?? "normal",
|
|
890
932
|
now
|
|
@@ -898,9 +940,10 @@ async function sendMessage(input) {
|
|
|
898
940
|
}
|
|
899
941
|
} catch {
|
|
900
942
|
}
|
|
943
|
+
const sentScope = strictSessionScopeFilter(sessionScope);
|
|
901
944
|
const result = await client.execute({
|
|
902
|
-
sql:
|
|
903
|
-
args: [id]
|
|
945
|
+
sql: `SELECT * FROM messages WHERE id = ?${sentScope.sql}`,
|
|
946
|
+
args: [id, ...sentScope.args]
|
|
904
947
|
});
|
|
905
948
|
return rowToMessage(result.rows[0]);
|
|
906
949
|
}
|
|
@@ -922,6 +965,7 @@ async function deliverCrossMachineMessage(messageId, targetDevice) {
|
|
|
922
965
|
fromAgent: msg.fromAgent,
|
|
923
966
|
targetAgent: msg.targetAgent,
|
|
924
967
|
targetProject: msg.targetProject,
|
|
968
|
+
sessionScope: msg.sessionScope,
|
|
925
969
|
content: msg.content,
|
|
926
970
|
priority: msg.priority,
|
|
927
971
|
createdAt: msg.createdAt
|
|
@@ -965,7 +1009,7 @@ async function deliverLocalMessage(messageId) {
|
|
|
965
1009
|
} catch {
|
|
966
1010
|
const newRetryCount = msg.retryCount + 1;
|
|
967
1011
|
if (newRetryCount >= MAX_RETRIES) {
|
|
968
|
-
await markFailed(messageId, "session unavailable after 10 retries");
|
|
1012
|
+
await markFailed(messageId, "session unavailable after 10 retries", msg.sessionScope);
|
|
969
1013
|
} else {
|
|
970
1014
|
await client.execute({
|
|
971
1015
|
sql: "UPDATE messages SET retry_count = ? WHERE id = ?",
|
|
@@ -975,11 +1019,13 @@ async function deliverLocalMessage(messageId) {
|
|
|
975
1019
|
return false;
|
|
976
1020
|
}
|
|
977
1021
|
}
|
|
978
|
-
async function markFailed(messageId, reason) {
|
|
1022
|
+
async function markFailed(messageId, reason, sessionScope) {
|
|
979
1023
|
const client = getClient();
|
|
1024
|
+
const scope = strictSessionScopeFilter(sessionScope);
|
|
980
1025
|
await client.execute({
|
|
981
|
-
sql:
|
|
982
|
-
|
|
1026
|
+
sql: `UPDATE messages SET status = 'failed', failed_at = ?, failure_reason = ?
|
|
1027
|
+
WHERE id = ?${scope.sql}`,
|
|
1028
|
+
args: [(/* @__PURE__ */ new Date()).toISOString(), reason, messageId, ...scope.args]
|
|
983
1029
|
});
|
|
984
1030
|
}
|
|
985
1031
|
|