@tomradex/doctor 0.0.0-stage → 0.14.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/LICENSE ADDED
@@ -0,0 +1,204 @@
1
+ Copyright 2026 Haoyuan Tang
2
+
3
+
4
+ Apache License
5
+ Version 2.0, January 2004
6
+ http://www.apache.org/licenses/
7
+
8
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
9
+
10
+ 1. Definitions.
11
+
12
+ "License" shall mean the terms and conditions for use, reproduction,
13
+ and distribution as defined by Sections 1 through 9 of this document.
14
+
15
+ "Licensor" shall mean the copyright owner or entity authorized by
16
+ the copyright owner that is granting the License.
17
+
18
+ "Legal Entity" shall mean the union of the acting entity and all
19
+ other entities that control, are controlled by, or are under common
20
+ control with that entity. For the purposes of this definition,
21
+ "control" means (i) the power, direct or indirect, to cause the
22
+ direction or management of such entity, whether by contract or
23
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
24
+ outstanding shares, or (iii) beneficial ownership of such entity.
25
+
26
+ "You" (or "Your") shall mean an individual or Legal Entity
27
+ exercising permissions granted by this License.
28
+
29
+ "Source" form shall mean the preferred form for making modifications,
30
+ including but not limited to software source code, documentation
31
+ source, and configuration files.
32
+
33
+ "Object" form shall mean any form resulting from mechanical
34
+ transformation or translation of a Source form, including but
35
+ not limited to compiled object code, generated documentation,
36
+ and conversions to other media types.
37
+
38
+ "Work" shall mean the work of authorship, whether in Source or
39
+ Object form, made available under the License, as indicated by a
40
+ copyright notice that is included in or attached to the work
41
+ (an example is provided in the Appendix below).
42
+
43
+ "Derivative Works" shall mean any work, whether in Source or Object
44
+ form, that is based on (or derived from) the Work and for which the
45
+ editorial revisions, annotations, elaborations, or other modifications
46
+ represent, as a whole, an original work of authorship. For the purposes
47
+ of this License, Derivative Works shall not include works that remain
48
+ separable from, or merely link (or bind by name) to the interfaces of,
49
+ the Work and Derivative Works thereof.
50
+
51
+ "Contribution" shall mean any work of authorship, including
52
+ the original version of the Work and any modifications or additions
53
+ to that Work or Derivative Works thereof, that is intentionally
54
+ submitted to Licensor for inclusion in the Work by the copyright owner
55
+ or by an individual or Legal Entity authorized to submit on behalf of
56
+ the copyright owner. For the purposes of this definition, "submitted"
57
+ means any form of electronic, verbal, or written communication sent
58
+ to the Licensor or its representatives, including but not limited to
59
+ communication on electronic mailing lists, source code control systems,
60
+ and issue tracking systems that are managed by, or on behalf of, the
61
+ Licensor for the purpose of discussing and improving the Work, but
62
+ excluding communication that is conspicuously marked or otherwise
63
+ designated in writing by the copyright owner as "Not a Contribution."
64
+
65
+ "Contributor" shall mean Licensor and any individual or Legal Entity
66
+ on behalf of whom a Contribution has been received by Licensor and
67
+ subsequently incorporated within the Work.
68
+
69
+ 2. Grant of Copyright License. Subject to the terms and conditions of
70
+ this License, each Contributor hereby grants to You a perpetual,
71
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
72
+ copyright license to reproduce, prepare Derivative Works of,
73
+ publicly display, publicly perform, sublicense, and distribute the
74
+ Work and such Derivative Works in Source or Object form.
75
+
76
+ 3. Grant of Patent License. Subject to the terms and conditions of
77
+ this License, each Contributor hereby grants to You a perpetual,
78
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
79
+ (except as stated in this section) patent license to make, have made,
80
+ use, offer to sell, sell, import, and otherwise transfer the Work,
81
+ where such license applies only to those patent claims licensable
82
+ by such Contributor that are necessarily infringed by their
83
+ Contribution(s) alone or by combination of their Contribution(s)
84
+ with the Work to which such Contribution(s) was submitted. If You
85
+ institute patent litigation against any entity (including a
86
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
87
+ or a Contribution incorporated within the Work constitutes direct
88
+ or contributory patent infringement, then any patent licenses
89
+ granted to You under this License for that Work shall terminate
90
+ as of the date such litigation is filed.
91
+
92
+ 4. Redistribution. You may reproduce and distribute copies of the
93
+ Work or Derivative Works thereof in any medium, with or without
94
+ modifications, and in Source or Object form, provided that You
95
+ meet the following conditions:
96
+
97
+ (a) You must give any other recipients of the Work or
98
+ Derivative Works a copy of this License; and
99
+
100
+ (b) You must cause any modified files to carry prominent notices
101
+ stating that You changed the files; and
102
+
103
+ (c) You must retain, in the Source form of any Derivative Works
104
+ that You distribute, all copyright, patent, trademark, and
105
+ attribution notices from the Source form of the Work,
106
+ excluding those notices that do not pertain to any part of
107
+ the Derivative Works; and
108
+
109
+ (d) If the Work includes a "NOTICE" text file as part of its
110
+ distribution, then any Derivative Works that You distribute must
111
+ include a readable copy of the attribution notices contained
112
+ within such NOTICE file, excluding those notices that do not
113
+ pertain to any part of the Derivative Works, in at least one
114
+ of the following places: within a NOTICE text file distributed
115
+ as part of the Derivative Works; within the Source form or
116
+ documentation, if provided along with the Derivative Works; or,
117
+ within a display generated by the Derivative Works, if and
118
+ wherever such third-party notices normally appear. The contents
119
+ of the NOTICE file are for informational purposes only and
120
+ do not modify the License. You may add Your own attribution
121
+ notices within Derivative Works that You distribute, alongside
122
+ or as an addendum to the NOTICE text from the Work, provided
123
+ that such additional attribution notices cannot be construed
124
+ as modifying the License.
125
+
126
+ You may add Your own copyright statement to Your modifications and
127
+ may provide additional or different license terms and conditions
128
+ for use, reproduction, or distribution of Your modifications, or
129
+ for any such Derivative Works as a whole, provided Your use,
130
+ reproduction, and distribution of the Work otherwise complies with
131
+ the conditions stated in this License.
132
+
133
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
134
+ any Contribution intentionally submitted for inclusion in the Work
135
+ by You to the Licensor shall be under the terms and conditions of
136
+ this License, without any additional terms or conditions.
137
+ Notwithstanding the above, nothing herein shall supersede or modify
138
+ the terms of any separate license agreement you may have executed
139
+ with Licensor regarding such Contributions.
140
+
141
+ 6. Trademarks. This License does not grant permission to use the trade
142
+ names, trademarks, service marks, or product names of the Licensor,
143
+ except as required for reasonable and customary use in describing the
144
+ origin of the Work and reproducing the content of the NOTICE file.
145
+
146
+ 7. Disclaimer of Warranty. Unless required by applicable law or
147
+ agreed to in writing, Licensor provides the Work (and each
148
+ Contributor provides its Contributions) on an "AS IS" BASIS,
149
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
150
+ implied, including, without limitation, any warranties or conditions
151
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
152
+ PARTICULAR PURPOSE. You are solely responsible for determining the
153
+ appropriateness of using or redistributing the Work and assume any
154
+ risks associated with Your exercise of permissions under this License.
155
+
156
+ 8. Limitation of Liability. In no event and under no legal theory,
157
+ whether in tort (including negligence), contract, or otherwise,
158
+ unless required by applicable law (such as deliberate and grossly
159
+ negligent acts) or agreed to in writing, shall any Contributor be
160
+ liable to You for damages, including any direct, indirect, special,
161
+ incidental, or consequential damages of any character arising as a
162
+ result of this License or out of the use or inability to use the
163
+ Work (including but not limited to damages for loss of goodwill,
164
+ work stoppage, computer failure or malfunction, or any and all
165
+ other commercial damages or losses), even if such Contributor
166
+ has been advised of the possibility of such damages.
167
+
168
+ 9. Accepting Warranty or Additional Liability. While redistributing
169
+ the Work or Derivative Works thereof, You may choose to offer,
170
+ and charge a fee for, acceptance of support, warranty, indemnity,
171
+ or other liability obligations and/or rights consistent with this
172
+ License. However, in accepting such obligations, You may act only
173
+ on Your own behalf and on Your sole responsibility, not on behalf
174
+ of any other Contributor, and only if You agree to indemnify,
175
+ defend, and hold each Contributor harmless for any liability
176
+ incurred by, or claims asserted against, such Contributor by reason
177
+ of your accepting any such warranty or additional liability.
178
+
179
+ END OF TERMS AND CONDITIONS
180
+
181
+ APPENDIX: How to apply the Apache License to your work.
182
+
183
+ To apply the Apache License to your work, attach the following
184
+ boilerplate notice, with the fields enclosed by brackets "[]"
185
+ replaced with your own identifying information. (Don't include
186
+ the brackets!) The text should be enclosed in the appropriate
187
+ comment syntax for the file format. We also recommend that a
188
+ file or class name and description of purpose be included on the
189
+ same "printed page" as the copyright notice for easier
190
+ identification within third-party archives.
191
+
192
+ Copyright [yyyy] [name of copyright owner]
193
+
194
+ Licensed under the Apache License, Version 2.0 (the "License");
195
+ you may not use this file except in compliance with the License.
196
+ You may obtain a copy of the License at
197
+
198
+ http://www.apache.org/licenses/LICENSE-2.0
199
+
200
+ Unless required by applicable law or agreed to in writing, software
201
+ distributed under the License is distributed on an "AS IS" BASIS,
202
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
203
+ See the License for the specific language governing permissions and
204
+ limitations under the License.
@@ -0,0 +1,20 @@
1
+ import { KnownIssue } from "./issues.js";
2
+ /** Read again at most this often: a new entry reaches everyone within hours, no release needed. */
3
+ export declare const CATALOG_MAX_AGE_MS: number;
4
+ /**
5
+ * The entries of a catalog that are well formed; a bad one is dropped, never
6
+ * the whole file. Entries are data — what they offer can only name verbs the
7
+ * panel knows — so a catalog can explain and point, but never run anything.
8
+ */
9
+ export declare function parseCatalog(raw: unknown): KnownIssue[];
10
+ export interface CachedCatalog {
11
+ fetchedAt: number;
12
+ issues: KnownIssue[];
13
+ }
14
+ export declare function readCache(file: string): CachedCatalog | null;
15
+ /** The catalog from tomrade.com; null when it could not be read, so the cache stays. */
16
+ export declare function fetchCatalog(url: string, fetcher?: typeof fetch): Promise<{
17
+ raw: unknown;
18
+ issues: KnownIssue[];
19
+ } | null>;
20
+ //# sourceMappingURL=catalog.d.ts.map
@@ -0,0 +1,11 @@
1
+ /** Keys, the home folder's name and email addresses never leave the machine in a report. */
2
+ export declare function scrub(text: string, home?: string): string;
3
+ export declare const TAIL_LINES = 120;
4
+ export declare const TAIL_CHARS = 24000;
5
+ /** The end of a log file, scrubbed: the last lines, never more than a few dozen KB. */
6
+ export declare function tail(file: string, lines?: number, chars?: number): string | null;
7
+ /** Newest first: the files in `dir` whose names pass `keep`. */
8
+ export declare function newestFiles(dir: string, keep?: (name: string) => boolean, limit?: number): string[];
9
+ /** Lines that look like errors, from the newest Tomrade logs: what a report shows first. */
10
+ export declare function errorLines(text: string, limit?: number): string[];
11
+ //# sourceMappingURL=evidence.d.ts.map
@@ -0,0 +1,7 @@
1
+ export { Doctor, DoctorConfig, DoctorOptions, DEFAULT_INCLUDE, REPORT_KINDS, Topic, fingerprint, type ReportKind, type Check, type CheckResult, type Diagnosis, type RemoteReport, type Report, type ReportInclude, type ReportView, type ReportsView, type SendResult, type Transport } from "./service.js";
2
+ export { parseCatalog, fetchCatalog, CATALOG_MAX_AGE_MS } from "./catalog.js";
3
+ export { Doctor as default } from "./service.js";
4
+ export { BUNDLED, KnownIssue, before, matches, type Evidence } from "./issues.js";
5
+ export { scrub, tail, newestFiles, errorLines } from "./evidence.js";
6
+ export { DOCTOR_WORDS, type Words } from "./words.js";
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,50 @@
1
+ import { z } from "zod";
2
+ import type { Context } from "cordis";
3
+ import type { CardAction, FindingCard, ThreadMessage, TurnIO } from "@tomradex/agent";
4
+ import { type LanguageTag } from "@tomradex/domain";
5
+ import type { Diagnosis } from "./service.js";
6
+ /** What the investigating agent may call: it reads, looks up, asks and concludes — never changes the setup or the work. */
7
+ export declare const INVESTIGATION_TOOLS: Set<string>;
8
+ export declare const CONCLUSION = "doctor/conclusion";
9
+ export declare const Conclusion: z.ZodObject<{
10
+ headline: z.ZodString;
11
+ explanation: z.ZodOptional<z.ZodString>;
12
+ confidence: z.ZodEnum<{
13
+ high: "high";
14
+ medium: "medium";
15
+ low: "low";
16
+ }>;
17
+ offer: z.ZodDefault<z.ZodArray<z.ZodEnum<{
18
+ "retry-with": "retry-with";
19
+ "sign-in": "sign-in";
20
+ install: "install";
21
+ settings: "settings";
22
+ recheck: "recheck";
23
+ }>>>;
24
+ }, z.core.$strip>;
25
+ export type Conclusion = z.infer<typeof Conclusion>;
26
+ export interface LogSource {
27
+ id: string;
28
+ file: string;
29
+ }
30
+ export interface InvestigationHost {
31
+ ctx: Context;
32
+ sources(engineId?: string): Promise<LogSource[]>;
33
+ latest(threadId: string): Diagnosis | null;
34
+ recheck(projectId: string, threadId: string, runId: string): Promise<Diagnosis>;
35
+ }
36
+ /** The tools a troubleshooting run gets; every other tool is refused inside one. */
37
+ export declare function investigationTools(host: InvestigationHost): import("@tomradex/tools").ToolDefinition<z.ZodObject<{}, z.core.$strip>>[];
38
+ /** Tomrade's newest log and the failing agent's own, by the names the tools use. */
39
+ export declare function logSources(ctx: Context, logDir: string | undefined, engineId?: string): Promise<LogSource[]>;
40
+ /** The investigating agent's first message: the job, the house rules, and every piece of evidence the checks gathered. */
41
+ export declare function brief(diagnosis: Diagnosis, failing: string | null, locale: LanguageTag): string;
42
+ /**
43
+ * The person's side of the investigation so far, as the investigating agent
44
+ * sees it: the brief folded into the first message, then each exchange.
45
+ */
46
+ export declare function investigationMessages(messages: ThreadMessage[], startSeq: number, briefText: string): ThreadMessage[];
47
+ /** The run's tools, cut down to the investigation's own. */
48
+ export declare function scopedTools(io: TurnIO): TurnIO["tools"];
49
+ export declare function conclusionCard(conclusion: Conclusion, actions: CardAction[]): FindingCard;
50
+ //# sourceMappingURL=investigate.d.ts.map
@@ -0,0 +1,56 @@
1
+ import { z } from "zod";
2
+ import { type LanguageTag } from "@tomradex/domain";
3
+ /**
4
+ * A problem someone already ran into and understood. Data only: what it
5
+ * offers names verbs the panel already knows, so a catalog fetched from
6
+ * tomrade.com can explain and point, never run anything.
7
+ */
8
+ export declare const KnownIssue: z.ZodObject<{
9
+ id: z.ZodString;
10
+ engine: z.ZodOptional<z.ZodString>;
11
+ when: z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
12
+ text: z.ZodString;
13
+ }, z.core.$strip>, z.ZodObject<{
14
+ fact: z.ZodString;
15
+ matches: z.ZodString;
16
+ }, z.core.$strip>]>>;
17
+ title: z.ZodObject<{
18
+ en: z.ZodString;
19
+ zh: z.ZodString;
20
+ }, z.core.$strip>;
21
+ explain: z.ZodObject<{
22
+ en: z.ZodString;
23
+ zh: z.ZodString;
24
+ }, z.core.$strip>;
25
+ confidence: z.ZodEnum<{
26
+ high: "high";
27
+ medium: "medium";
28
+ low: "low";
29
+ }>;
30
+ offer: z.ZodDefault<z.ZodArray<z.ZodEnum<{
31
+ "retry-with": "retry-with";
32
+ "sign-in": "sign-in";
33
+ install: "install";
34
+ settings: "settings";
35
+ recheck: "recheck";
36
+ }>>>;
37
+ fixedIn: z.ZodOptional<z.ZodString>;
38
+ }, z.core.$strip>;
39
+ export type KnownIssue = z.infer<typeof KnownIssue>;
40
+ export interface Evidence {
41
+ engineId?: string;
42
+ /** Error lines and their details, from the failed turn and the test turn. */
43
+ texts: string[];
44
+ facts: Record<string, string>;
45
+ version: string;
46
+ }
47
+ /** Whether `version` (1.2.3, v-prefixed or not) comes before `fixed`. */
48
+ export declare function before(version: string, fixed: string): boolean;
49
+ export declare function matches(issue: KnownIssue, evidence: Evidence): boolean;
50
+ export declare const said: (text: {
51
+ en: string;
52
+ zh: string;
53
+ }, locale: LanguageTag) => string;
54
+ /** The problems known when this release was made. A newer catalog from tomrade.com adds to them. */
55
+ export declare const BUNDLED: KnownIssue[];
56
+ //# sourceMappingURL=issues.d.ts.map
@@ -0,0 +1 @@
1
+ throw new Error("@tomradex/doctor is Tomrade's own code: a full-mode plugin gets the running app's copy, so load the plugin in Tomrade");
@@ -0,0 +1,287 @@
1
+ import { Context, Service } from "cordis";
2
+ import { z } from "zod";
3
+ import type { CardAction, ChecklistCard, Engine, FindingCard, ThreadSummary, TurnInput, TurnIO, TurnResult } from "@tomradex/agent";
4
+ import { KnownIssue } from "./issues.js";
5
+ import { type LanguageTag } from "@tomradex/domain";
6
+ import { type Words } from "./words.js";
7
+ /** What a troubleshooting thread is about: a failed turn, or nothing in particular. */
8
+ export declare const Topic: z.ZodObject<{
9
+ threadId: z.ZodOptional<z.ZodString>;
10
+ runId: z.ZodOptional<z.ZodString>;
11
+ engineId: z.ZodOptional<z.ZodString>;
12
+ error: z.ZodOptional<z.ZodString>;
13
+ details: z.ZodOptional<z.ZodString>;
14
+ }, z.core.$strip>;
15
+ export type Topic = z.infer<typeof Topic>;
16
+ export declare const DoctorOptions: z.ZodObject<{
17
+ topic: z.ZodOptional<z.ZodObject<{
18
+ threadId: z.ZodOptional<z.ZodString>;
19
+ runId: z.ZodOptional<z.ZodString>;
20
+ engineId: z.ZodOptional<z.ZodString>;
21
+ error: z.ZodOptional<z.ZodString>;
22
+ details: z.ZodOptional<z.ZodString>;
23
+ }, z.core.$strip>>;
24
+ investigator: z.ZodOptional<z.ZodString>;
25
+ }, z.core.$strip>;
26
+ export interface CheckResult {
27
+ state: "ok" | "warn" | "fail" | "skip";
28
+ /** One line, in the person's language. */
29
+ line: string;
30
+ facts?: Record<string, string>;
31
+ /** What can be done about a warning or a failure. */
32
+ actions?: CardAction[];
33
+ /** Longer text for the report: an error's details, say. */
34
+ evidence?: string;
35
+ }
36
+ /** One thing the troubleshooter looks at. Plugins add their own. */
37
+ export interface Check {
38
+ id: string;
39
+ title(words: Words): string;
40
+ /** Whether it says anything about this topic; absent, it always runs. */
41
+ applies?(topic: Topic): boolean;
42
+ run(topic: Topic, signal: AbortSignal): Promise<CheckResult>;
43
+ }
44
+ /** Everything one round of checks found, kept for the report. */
45
+ export interface Diagnosis {
46
+ topic: Topic;
47
+ at: number;
48
+ version: string;
49
+ rows: {
50
+ id: string;
51
+ title: string;
52
+ state: ChecklistCard["rows"][number]["state"];
53
+ line: string;
54
+ evidence?: string;
55
+ }[];
56
+ facts: Record<string, string>;
57
+ issues: string[];
58
+ findings: FindingCard[];
59
+ logs: {
60
+ source: string;
61
+ text: string;
62
+ }[];
63
+ /** The agent that looked into it, once one did. */
64
+ investigator?: string;
65
+ }
66
+ export interface ReportInclude {
67
+ environment: boolean;
68
+ checks: boolean;
69
+ error: boolean;
70
+ logs: boolean;
71
+ /** The failed conversation itself: off unless the person ticks it. */
72
+ conversation: boolean;
73
+ }
74
+ export declare const DEFAULT_INCLUDE: ReportInclude;
75
+ /** A troubleshooting report is a bug; the person may also write in with feedback or an idea. */
76
+ export declare const REPORT_KINDS: readonly ["bug", "feedback", "idea"];
77
+ export type ReportKind = (typeof REPORT_KINDS)[number];
78
+ /** What reaches Tomrade's developer: the person saw this text, section by section, before it went. */
79
+ export interface Report {
80
+ code: string;
81
+ /** Absent: a troubleshooting report, which is a bug. */
82
+ kind?: ReportKind;
83
+ createdAt: string;
84
+ fingerprint: string;
85
+ summary: string;
86
+ engine: string | null;
87
+ app: {
88
+ version: string;
89
+ os: string;
90
+ arch: string;
91
+ locale: string;
92
+ };
93
+ sections: {
94
+ id: keyof ReportInclude | "note";
95
+ title: string;
96
+ text: string;
97
+ }[];
98
+ }
99
+ export interface SendResult {
100
+ code: string;
101
+ state: "sent" | "queued";
102
+ /** Why it waits, when it does. */
103
+ reason?: string;
104
+ }
105
+ /** Puts a report in Tomrade's backend; the default goes through the signed-in account. */
106
+ export type Transport = (report: Report) => Promise<void>;
107
+ /** A sent report as the backend holds it: the developer sets its status, reply and fix. */
108
+ export interface RemoteReport {
109
+ code: string;
110
+ created_at: string;
111
+ summary: string;
112
+ engine: string | null;
113
+ status: string;
114
+ reply: string | null;
115
+ replied_at: string | null;
116
+ fixed_in: string | null;
117
+ }
118
+ export interface ReportView {
119
+ code: string;
120
+ kind?: ReportKind;
121
+ createdAt: string;
122
+ summary: string;
123
+ engine: string | null;
124
+ /** queued: still on this machine; sent: gone, its status not read yet; else as the developer set it. */
125
+ status: "queued" | "sent" | "new" | "triaged" | "fixed" | "wontfix" | "duplicate";
126
+ reply?: string;
127
+ repliedAt?: string;
128
+ fixedIn?: string;
129
+ /** Fixed in a release this machine already runs. */
130
+ fixedHere?: boolean;
131
+ /** A reply or a decision the person has not seen yet. */
132
+ unread: boolean;
133
+ }
134
+ export interface ReportsView {
135
+ signedIn: boolean;
136
+ reports: ReportView[];
137
+ unread: number;
138
+ }
139
+ export declare const DoctorConfig: z.ZodObject<{
140
+ dataDir: z.ZodString;
141
+ logDir: z.ZodOptional<z.ZodString>;
142
+ version: z.ZodDefault<z.ZodString>;
143
+ catalogUrl: z.ZodDefault<z.ZodString>;
144
+ }, z.core.$strip>;
145
+ export type DoctorConfig = z.infer<typeof DoctorConfig>;
146
+ declare module "cordis" {
147
+ interface Context {
148
+ doctor: Doctor;
149
+ }
150
+ interface Events {
151
+ /** A report reached the backend, or waits to. */
152
+ "doctor/report"(result: SendResult): void;
153
+ }
154
+ }
155
+ declare module "@tomradex/ipc" {
156
+ interface Channels {
157
+ "doctor.start": (projectId: string, from?: {
158
+ threadId: string;
159
+ runId?: string;
160
+ } | null) => {
161
+ threadId: string;
162
+ };
163
+ "doctor.preview": (projectId: string, threadId: string, include?: Partial<ReportInclude>, note?: string) => Report;
164
+ "doctor.send": (projectId: string, threadId: string, include?: Partial<ReportInclude>, note?: string) => SendResult;
165
+ "doctor.investigate": (projectId: string, threadId: string, engineId: string) => void;
166
+ "doctor.reports": () => ReportsView;
167
+ "doctor.markRead": () => void;
168
+ "doctor.deleteReport": (code: string) => void;
169
+ "doctor.flush": () => number;
170
+ "doctor.feedbackPreview": (kind: ReportKind, text: string) => Report;
171
+ "doctor.sendFeedback": (kind: ReportKind, text: string) => SendResult;
172
+ }
173
+ }
174
+ /** Digits, hex runs and paths vary between two people hitting the same thing; the rest says what it is. */
175
+ export declare function fingerprint(engine: string | null | undefined, error: string | undefined, issue?: string): string;
176
+ export declare class Doctor extends Service {
177
+ config: DoctorConfig;
178
+ static provide: string;
179
+ static inject: string[];
180
+ static Config: z.ZodObject<{
181
+ dataDir: z.ZodString;
182
+ logDir: z.ZodOptional<z.ZodString>;
183
+ version: z.ZodDefault<z.ZodString>;
184
+ catalogUrl: z.ZodDefault<z.ZodString>;
185
+ }, z.core.$strip>;
186
+ private checks;
187
+ private catalog;
188
+ private retryTimer;
189
+ /** Swapped in tests; otherwise the account's backend. */
190
+ transport: Transport | null;
191
+ /** Swapped in tests; otherwise the signed-in account's own reports. */
192
+ fetchReports: (() => Promise<RemoteReport[] | null>) | null;
193
+ private remote;
194
+ private unread;
195
+ constructor(ctx: Context, config: DoctorConfig);
196
+ [Service.init](): void;
197
+ locale(): LanguageTag;
198
+ words(): Words;
199
+ /** A check of a plugin's own — sync, a provider, a service. */
200
+ check(check: Check): () => void;
201
+ /** A known problem, from a plugin or a newer catalog; a later one with the same id replaces it. */
202
+ issue(issue: KnownIssue): () => void;
203
+ /** Bundled and plugin issues, with the fetched catalog's newer word on the same id. */
204
+ issues(): KnownIssue[];
205
+ private catalogFile;
206
+ /** The catalog from tomrade.com, at most every few hours; a failed read keeps what was cached. */
207
+ refreshCatalog(force?: boolean, fetcher?: typeof fetch): Promise<number>;
208
+ /** A troubleshooting thread, about a failed turn or nothing in particular, already checking. */
209
+ start(projectId: string, from: {
210
+ threadId: string;
211
+ runId?: string;
212
+ } | null): ThreadSummary;
213
+ private troubleshoot;
214
+ /** The failed turn: its engine, its error line and details. */
215
+ topicOf(projectId: string, threadId: string, runId?: string): Topic;
216
+ /**
217
+ * The troubleshooter as an engine: it conducts only the threads it opens
218
+ * (no capabilities, so no picker offers it), and each turn checks again —
219
+ * a checklist that fills in as it goes, then what was found.
220
+ */
221
+ engine(): Engine;
222
+ /** One round of checks inside a run: the checklist card fills in, the diagnosis is kept for the report. */
223
+ runChecks(projectId: string, threadId: string, runId: string, topic: Topic, signal?: AbortSignal, cardId?: string): Promise<Diagnosis>;
224
+ recheck(projectId: string, threadId: string, runId: string): Promise<Diagnosis>;
225
+ sources(engineId?: string): Promise<import("./investigate.js").LogSource[]>;
226
+ /** Agents that could look into it: ready, able to hold a conversation, and not the one that failed. */
227
+ investigators(topic: Topic): Promise<string[]>;
228
+ /** The person picked an agent to look into it: the thread remembers it, and the agent starts. */
229
+ investigate(projectId: string, threadId: string, engineId: string): void;
230
+ private stateFile;
231
+ /** Hands the turn to the investigating agent: its own turn, held to the investigation's tools. */
232
+ delegate(input: TurnInput, io: TurnIO, engineId: string): Promise<TurnResult>;
233
+ /** What a known issue or a conclusion offers, as buttons about this topic. */
234
+ private actionsFor;
235
+ diagnose(projectId: string, topic: Topic, show?: (rows: ChecklistCard["rows"]) => void, signal?: AbortSignal): Promise<Diagnosis>;
236
+ private engineTitle;
237
+ private engineFacts;
238
+ /** Tails of Tomrade's newest log and the failing agent's own. */
239
+ private logs;
240
+ /** One real turn on the engine: does it answer now? */
241
+ probe(projectId: string, engineId: string, signal: AbortSignal): Promise<{
242
+ ok: boolean;
243
+ ms: number;
244
+ error?: string;
245
+ details?: string;
246
+ }>;
247
+ private findings;
248
+ /** Tomrade itself first, then the agents in question, then everything else that applies. */
249
+ private checksFor;
250
+ /** The failing engine; with no topic, every agent the person has installed — a missing one is not a problem. */
251
+ private engineIdsFor;
252
+ private engineCheck;
253
+ private builtInChecks;
254
+ private file;
255
+ private save;
256
+ latest(threadId: string): Diagnosis | null;
257
+ /** The report about a troubleshooting thread, exactly as it would be sent. */
258
+ report(projectId: string, threadId: string, include?: Partial<ReportInclude>, note?: string): Report;
259
+ private transcript;
260
+ /** What the person wrote in, with nothing else read from this machine but the app's version and system. */
261
+ feedbackReport(kind: ReportKind, text: string): Report;
262
+ /** Feedback goes the way reports go: kept in the outbox until the backend has it, then answered under My reports. */
263
+ sendFeedback(kind: ReportKind, text: string): Promise<SendResult>;
264
+ /** Saved first, then sent: a report the backend can't take yet waits in the outbox and goes later. */
265
+ send(projectId: string, threadId: string, include?: Partial<ReportInclude>, note?: string): Promise<SendResult>;
266
+ private dispatch;
267
+ private deliver;
268
+ /** Whatever waits in the outbox, oldest first. */
269
+ flush(): Promise<number>;
270
+ pending(): number;
271
+ private signedIn;
272
+ private remoteReports;
273
+ private readJson;
274
+ /** What the person last saw of each report; a newer reply or decision reads as unread. */
275
+ private stamp;
276
+ /** Every report this person sent from here or anywhere, newest first: waiting, sent, answered. */
277
+ reports(): Promise<ReportsView>;
278
+ refreshReports(): Promise<void>;
279
+ private setUnread;
280
+ /** The person opened their reports: what is there now is seen. */
281
+ markRead(): Promise<void>;
282
+ /** Gone from this machine and, when signed in, from the backend too. */
283
+ deleteReport(code: string): Promise<void>;
284
+ private remember;
285
+ private backend;
286
+ }
287
+ //# sourceMappingURL=service.d.ts.map
@@ -0,0 +1,63 @@
1
+ export declare const DOCTOR_WORDS: import("@tomradex/domain").WordBook<{
2
+ readonly engineTitle: "Troubleshooter";
3
+ readonly command: "Troubleshoot a problem…";
4
+ readonly commandGroup: "Help";
5
+ readonly statusItem: "Troubleshoot";
6
+ readonly statusTitle: "Something not working? Let Tomrade check what it can and tell you what to do";
7
+ readonly threadTitle: "Troubleshooting: {{what}}";
8
+ readonly general: "a problem";
9
+ readonly askFailure: "Find out why {{engine}} failed just now.";
10
+ readonly askGeneral: "Check whether anything is wrong.";
11
+ readonly checksTitle: "What I checked";
12
+ readonly checkApp: "Tomrade";
13
+ readonly checkModels: "Models";
14
+ readonly checkMcp: "Tomrade's tools for local agents";
15
+ readonly checkSync: "Account and sync";
16
+ readonly checkProbe: "A test turn with {{title}}";
17
+ readonly appLine: "{{version}} · {{os}}";
18
+ readonly engineReady: "ready";
19
+ readonly cliFound: "{{path}}";
20
+ readonly cliFoundVersion: "{{path}} ({{version}})";
21
+ readonly noProfiles: "no model connected";
22
+ readonly modelOk: "the model answers";
23
+ readonly modelsOk: "all {{n}} models answer";
24
+ readonly modelFails: "{{title}}: {{detail}}";
25
+ readonly mcpOn: "serving at {{url}}";
26
+ readonly mcpOff: "not running — local agents cannot use Tomrade's tools";
27
+ readonly syncOff: "not signed in";
28
+ readonly syncState: "{{status}}";
29
+ readonly syncStatePending: "{{status}} · {{pending}} change(s) waiting to upload";
30
+ readonly probeOk: "answered in {{seconds}} s";
31
+ readonly probeFailed: "failed: {{error}}";
32
+ readonly probeSkipped: "skipped — the agent is not ready";
33
+ readonly nothingFound: "Nothing obviously wrong";
34
+ readonly nothingFoundBody: "Every check passed. If the problem is still there, say what happens in a message here, or send this report to Tomrade's developer.";
35
+ readonly stillFailing: "{{engine}} still fails";
36
+ readonly recovered: "{{engine}} works again";
37
+ readonly recoveredBody: "The test turn answered. Try your message again.";
38
+ readonly actionSignIn: "Sign in to {{engine}}";
39
+ readonly actionInstall: "Install {{engine}}";
40
+ readonly actionSettings: "{{engine}} settings";
41
+ readonly actionModelSettings: "Open model settings";
42
+ readonly actionRetryWith: "Continue with another agent";
43
+ readonly actionRecheck: "Check again";
44
+ readonly actionReport: "Send to the developer";
45
+ readonly recheckSay: "Check again.";
46
+ readonly actionInvestigate: "Let an agent look into it";
47
+ readonly investigateNote: "It reads the error, the checks and the log excerpts above, and may look the error up online. What it reads goes to that agent's model provider — at work, pick one your company allows.";
48
+ readonly investigateAsk: "{{title}}, please look into this.";
49
+ readonly noInvestigator: "That agent can't look into it right now.";
50
+ readonly reportsCommand: "My troubleshooting reports";
51
+ readonly statusReply: "A reply to your report";
52
+ readonly statusReplies: "{{n}} replies to your reports";
53
+ readonly noProject: "Create or open a project first";
54
+ readonly writeSomething: "Write something first";
55
+ readonly sectionNote: "Note";
56
+ readonly sectionError: "Error";
57
+ readonly sectionChecks: "Checks";
58
+ readonly sectionEnvironment: "Environment";
59
+ readonly sectionLogs: "Logs";
60
+ readonly sectionConversation: "Conversation";
61
+ }>;
62
+ export type Words = ReturnType<typeof DOCTOR_WORDS>;
63
+ //# sourceMappingURL=words.d.ts.map
package/package.json CHANGED
@@ -1,6 +1,42 @@
1
1
  {
2
2
  "name": "@tomradex/doctor",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.14.0",
4
+ "type": "module",
5
+ "author": "Haoyuan Tang",
6
+ "engines": {
7
+ "node": ">=22"
8
+ },
9
+ "publishConfig": {
10
+ "access": "public"
11
+ },
12
+ "license": "Apache-2.0",
13
+ "description": "The troubleshooter: checks what it can when something fails, says what to do about it, and sends a report the person has read to Tomrade's developer — declarations for full-mode plugins; Tomrade provides the code at run time",
14
+ "keywords": [
15
+ "tomrade",
16
+ "tomrade-plugin",
17
+ "types"
18
+ ],
19
+ "types": "./dist/index.d.ts",
20
+ "exports": {
21
+ ".": {
22
+ "types": "./dist/index.d.ts",
23
+ "default": "./dist/runtime.js"
24
+ }
25
+ },
26
+ "files": [
27
+ "dist"
28
+ ],
29
+ "dependencies": {
30
+ "@tomradex/agent": "0.14.0",
31
+ "@tomradex/contributions": "0.14.0",
32
+ "@tomradex/domain": "0.2.16",
33
+ "@tomradex/ipc": "0.14.0",
34
+ "@tomradex/llm": "0.14.0",
35
+ "@tomradex/mcp": "0.14.0",
36
+ "@tomradex/projects": "0.14.0",
37
+ "@tomradex/settings": "0.14.0",
38
+ "@tomradex/tools": "0.14.0",
39
+ "cordis": "4.0.0-rc.8",
40
+ "zod": "^4.4.3"
41
+ }
42
+ }
package/README.md DELETED
@@ -1,3 +0,0 @@
1
- # Temporary Holding Version
2
-
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.