@telepat/ideon 0.1.0 → 0.1.5
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 +21 -0
- package/README.md +25 -12
- package/dist/ideon.js +161 -7
- package/package.json +2 -2
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Telepat contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -8,7 +8,14 @@ ooooo oooooooooo. oooooooooooo .oooooo. ooooo ooo
|
|
|
8
8
|
o888o o888bood8P' o888ooooood8 `Y8bood8P' o8o `8
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
#
|
|
11
|
+
# AI Writer Extraordinaire
|
|
12
|
+
|
|
13
|
+
[](https://github.com/telepat-io/ideon/actions/workflows/ci.yml)
|
|
14
|
+
[](https://codecov.io/gh/telepat-io/ideon)
|
|
15
|
+
[](https://www.npmjs.com/package/@telepat/ideon)
|
|
16
|
+
[](https://www.npmjs.com/package/@telepat/ideon)
|
|
17
|
+
[](https://docs.telepat.io/ideon)
|
|
18
|
+
[](https://github.com/telepat-io/ideon/blob/main/LICENSE)
|
|
12
19
|
|
|
13
20
|
Ideon is a TypeScript CLI that turns an idea into one or more Markdown outputs, with optional generated images for article runs.
|
|
14
21
|
|
|
@@ -30,16 +37,16 @@ Prerequisites:
|
|
|
30
37
|
- Node.js 20+
|
|
31
38
|
- npm 10+
|
|
32
39
|
|
|
33
|
-
Install
|
|
40
|
+
Install globally:
|
|
34
41
|
|
|
35
42
|
```bash
|
|
36
|
-
npm
|
|
43
|
+
npm i -g @telepat/ideon
|
|
37
44
|
```
|
|
38
45
|
|
|
39
|
-
|
|
46
|
+
Verify installation:
|
|
40
47
|
|
|
41
48
|
```bash
|
|
42
|
-
|
|
49
|
+
ideon --help
|
|
43
50
|
```
|
|
44
51
|
|
|
45
52
|
## Getting Started
|
|
@@ -47,25 +54,25 @@ npm run dev -- --help
|
|
|
47
54
|
1. Configure credentials interactively:
|
|
48
55
|
|
|
49
56
|
```bash
|
|
50
|
-
|
|
57
|
+
ideon settings
|
|
51
58
|
```
|
|
52
59
|
|
|
53
60
|
2. Generate your first article:
|
|
54
61
|
|
|
55
62
|
```bash
|
|
56
|
-
|
|
63
|
+
ideon write "How small editorial teams can productionize AI writing"
|
|
57
64
|
```
|
|
58
65
|
|
|
59
66
|
3. Generate multi-output runs:
|
|
60
67
|
|
|
61
68
|
```bash
|
|
62
|
-
|
|
69
|
+
ideon write "How small editorial teams can productionize AI writing" --target article=1 --target x-post=2 --style professional
|
|
63
70
|
```
|
|
64
71
|
|
|
65
72
|
4. Run a safe pipeline dry run (no provider calls):
|
|
66
73
|
|
|
67
74
|
```bash
|
|
68
|
-
|
|
75
|
+
ideon write --dry-run "How AI changes technical publishing"
|
|
69
76
|
```
|
|
70
77
|
|
|
71
78
|
## Core Commands
|
|
@@ -85,7 +92,7 @@ ideon preview
|
|
|
85
92
|
Serve the latest generated article locally with assets and open it in your browser:
|
|
86
93
|
|
|
87
94
|
```bash
|
|
88
|
-
|
|
95
|
+
ideon preview
|
|
89
96
|
```
|
|
90
97
|
|
|
91
98
|
This launches the new React preview app (served from `dist/preview`) and the preview API server.
|
|
@@ -93,7 +100,7 @@ This launches the new React preview app (served from `dist/preview`) and the pre
|
|
|
93
100
|
You can also preview a specific article and choose a port:
|
|
94
101
|
|
|
95
102
|
```bash
|
|
96
|
-
|
|
103
|
+
ideon preview ./output/my-article.md --port 4173
|
|
97
104
|
```
|
|
98
105
|
|
|
99
106
|
If you are iterating on preview UI code in `src/preview-app`, rebuild client assets after UI changes:
|
|
@@ -136,6 +143,12 @@ npm run pricing:refresh
|
|
|
136
143
|
- Start docs locally: `npm run docs:start`
|
|
137
144
|
- Build docs: `npm run docs:build`
|
|
138
145
|
|
|
146
|
+
Links:
|
|
147
|
+
|
|
148
|
+
- GitHub repository: [telepat-io/ideon](https://github.com/telepat-io/ideon)
|
|
149
|
+
- npm package: [@telepat/ideon](https://www.npmjs.com/package/@telepat/ideon)
|
|
150
|
+
- Documentation site: [docs.telepat.io/ideon](https://docs.telepat.io/ideon)
|
|
151
|
+
|
|
139
152
|
Key docs:
|
|
140
153
|
|
|
141
154
|
- CLI commands: `docs-site/docs/reference/cli-reference.md`
|
|
@@ -146,4 +159,4 @@ Key docs:
|
|
|
146
159
|
|
|
147
160
|
GitHub Pages URL:
|
|
148
161
|
|
|
149
|
-
-
|
|
162
|
+
- [https://docs.telepat.io/ideon](https://docs.telepat.io/ideon)
|
package/dist/ideon.js
CHANGED
|
@@ -36,11 +36,15 @@ var baseT2ISettingsSchema = z.object({
|
|
|
36
36
|
modelId: z.string().default("black-forest-labs/flux-schnell"),
|
|
37
37
|
inputOverrides: z.record(z.string(), z.unknown()).default({})
|
|
38
38
|
});
|
|
39
|
+
var notificationsSettingsSchema = z.object({
|
|
40
|
+
enabled: z.boolean().default(false)
|
|
41
|
+
});
|
|
39
42
|
var appSettingsSchema = z.object({
|
|
40
43
|
model: z.string().default("moonshotai/kimi-k2.5"),
|
|
41
44
|
modelSettings: modelSettingsSchema.default(modelSettingsSchema.parse({})),
|
|
42
45
|
modelRequestTimeoutMs: z.number().int().positive().default(9e4),
|
|
43
46
|
t2i: baseT2ISettingsSchema.default(baseT2ISettingsSchema.parse({})),
|
|
47
|
+
notifications: notificationsSettingsSchema.default(notificationsSettingsSchema.parse({})),
|
|
44
48
|
markdownOutputDir: z.string().default("/output"),
|
|
45
49
|
assetOutputDir: z.string().default("/output/assets"),
|
|
46
50
|
contentTargets: z.array(contentTargetSchema).min(1).refine((targets) => targets.filter((target) => target.role === "primary").length === 1, {
|
|
@@ -57,6 +61,7 @@ var envSettingsSchema = z.object({
|
|
|
57
61
|
maxTokens: z.number().int().positive().optional(),
|
|
58
62
|
topP: z.number().min(0).max(1).optional(),
|
|
59
63
|
modelRequestTimeoutMs: z.number().int().positive().optional(),
|
|
64
|
+
notificationsEnabled: z.boolean().optional(),
|
|
60
65
|
markdownOutputDir: z.string().optional(),
|
|
61
66
|
assetOutputDir: z.string().optional(),
|
|
62
67
|
style: z.enum(writingStyleValues).optional(),
|
|
@@ -78,6 +83,19 @@ function parseNumber(value2) {
|
|
|
78
83
|
const parsed = Number(value2);
|
|
79
84
|
return Number.isFinite(parsed) ? parsed : void 0;
|
|
80
85
|
}
|
|
86
|
+
function parseBoolean(value2) {
|
|
87
|
+
if (!value2) {
|
|
88
|
+
return void 0;
|
|
89
|
+
}
|
|
90
|
+
const normalized = value2.trim().toLowerCase();
|
|
91
|
+
if (normalized === "true") {
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
94
|
+
if (normalized === "false") {
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
return void 0;
|
|
98
|
+
}
|
|
81
99
|
function readEnvSettings(env = process.env) {
|
|
82
100
|
return envSettingsSchema.parse({
|
|
83
101
|
openRouterApiKey: env.IDEON_OPENROUTER_API_KEY,
|
|
@@ -87,6 +105,7 @@ function readEnvSettings(env = process.env) {
|
|
|
87
105
|
maxTokens: parseNumber(env.IDEON_MAX_TOKENS),
|
|
88
106
|
topP: parseNumber(env.IDEON_TOP_P),
|
|
89
107
|
modelRequestTimeoutMs: parseNumber(env.IDEON_MODEL_REQUEST_TIMEOUT_MS),
|
|
108
|
+
notificationsEnabled: parseBoolean(env.IDEON_NOTIFICATIONS_ENABLED),
|
|
90
109
|
markdownOutputDir: env.IDEON_MARKDOWN_OUTPUT_DIR,
|
|
91
110
|
assetOutputDir: env.IDEON_ASSET_OUTPUT_DIR,
|
|
92
111
|
style: env.IDEON_STYLE,
|
|
@@ -896,6 +915,10 @@ function SettingsFlow({ initialSettings, initialSecrets, onDone }) {
|
|
|
896
915
|
label: `LLM model: ${settings.model}`,
|
|
897
916
|
value: "llm-model"
|
|
898
917
|
},
|
|
918
|
+
{
|
|
919
|
+
label: `Notifications > OS notifications enabled: ${settings.notifications.enabled ? "true" : "false"}`,
|
|
920
|
+
value: "notifications-enabled"
|
|
921
|
+
},
|
|
899
922
|
{
|
|
900
923
|
label: `Temperature: ${settings.modelSettings.temperature}`,
|
|
901
924
|
value: "temperature"
|
|
@@ -1018,6 +1041,9 @@ function handleMenuSelect(action, settings, secrets, setEditing, setShowModelSel
|
|
|
1018
1041
|
case "llm-model":
|
|
1019
1042
|
setEditing({ key: action, label: "LLM model", value: settings.model });
|
|
1020
1043
|
return;
|
|
1044
|
+
case "notifications-enabled":
|
|
1045
|
+
setEditing({ key: action, label: "Notifications > OS notifications enabled (true|false)", value: String(settings.notifications.enabled) });
|
|
1046
|
+
return;
|
|
1021
1047
|
case "temperature":
|
|
1022
1048
|
setEditing({ key: action, label: "Temperature", value: String(settings.modelSettings.temperature) });
|
|
1023
1049
|
return;
|
|
@@ -1069,6 +1095,17 @@ function applyEdit(action, value2, settings, secrets, setSettings, setSecrets) {
|
|
|
1069
1095
|
setSettings({ ...settings, model: value2.trim() || settings.model });
|
|
1070
1096
|
return;
|
|
1071
1097
|
}
|
|
1098
|
+
if (action === "notifications-enabled") {
|
|
1099
|
+
const parsed = parseBooleanOrFallback(value2, settings.notifications.enabled);
|
|
1100
|
+
setSettings({
|
|
1101
|
+
...settings,
|
|
1102
|
+
notifications: {
|
|
1103
|
+
...settings.notifications,
|
|
1104
|
+
enabled: parsed
|
|
1105
|
+
}
|
|
1106
|
+
});
|
|
1107
|
+
return;
|
|
1108
|
+
}
|
|
1072
1109
|
if (action === "temperature") {
|
|
1073
1110
|
const nextTemperature = clampNumber2(parseNumberOrFallback(value2, settings.modelSettings.temperature), 0, 2);
|
|
1074
1111
|
setSettings({
|
|
@@ -1147,6 +1184,16 @@ function parseNumberOrFallback(value2, fallback) {
|
|
|
1147
1184
|
function clampNumber2(value2, minimum, maximum) {
|
|
1148
1185
|
return Math.min(maximum, Math.max(minimum, value2));
|
|
1149
1186
|
}
|
|
1187
|
+
function parseBooleanOrFallback(value2, fallback) {
|
|
1188
|
+
const normalized = value2.trim().toLowerCase();
|
|
1189
|
+
if (normalized === "true") {
|
|
1190
|
+
return true;
|
|
1191
|
+
}
|
|
1192
|
+
if (normalized === "false") {
|
|
1193
|
+
return false;
|
|
1194
|
+
}
|
|
1195
|
+
return fallback;
|
|
1196
|
+
}
|
|
1150
1197
|
|
|
1151
1198
|
// src/config/secretStore.ts
|
|
1152
1199
|
import keytar from "keytar";
|
|
@@ -3491,6 +3538,13 @@ async function resolveRunInput(input) {
|
|
|
3491
3538
|
...job?.settings ?? {},
|
|
3492
3539
|
...envSettings.model ? { model: envSettings.model } : {},
|
|
3493
3540
|
...envSettings.modelRequestTimeoutMs !== void 0 ? { modelRequestTimeoutMs: envSettings.modelRequestTimeoutMs } : {},
|
|
3541
|
+
...envSettings.notificationsEnabled !== void 0 ? {
|
|
3542
|
+
notifications: {
|
|
3543
|
+
...savedSettings.notifications,
|
|
3544
|
+
...job?.settings?.notifications ?? {},
|
|
3545
|
+
enabled: envSettings.notificationsEnabled
|
|
3546
|
+
}
|
|
3547
|
+
} : {},
|
|
3494
3548
|
...envSettings.temperature !== void 0 || envSettings.maxTokens !== void 0 || envSettings.topP !== void 0 ? {
|
|
3495
3549
|
modelSettings: {
|
|
3496
3550
|
...savedSettings.modelSettings,
|
|
@@ -3909,9 +3963,9 @@ function buildUrlResolutionMessages(options) {
|
|
|
3909
3963
|
role: "system",
|
|
3910
3964
|
content: [
|
|
3911
3965
|
"You are a web research assistant for editorial linking.",
|
|
3912
|
-
"Use web search to find the best single URL
|
|
3913
|
-
"Start with the exact
|
|
3914
|
-
"Reject results that do not directly match the
|
|
3966
|
+
"Use web search to find the best single URL to attach as a link to the provided text in context.",
|
|
3967
|
+
"Start with the exact input text as the search phrase before trying broader variants.",
|
|
3968
|
+
"Reject results that do not directly match the topic and paragraph meaning.",
|
|
3915
3969
|
"Prefer canonical, trustworthy, stable sources that match the paragraph intent.",
|
|
3916
3970
|
'Return only one line: the selected URL, or "none" when no strong match exists.',
|
|
3917
3971
|
"Do not return markdown, explanations, bullets, or extra text."
|
|
@@ -3922,15 +3976,12 @@ function buildUrlResolutionMessages(options) {
|
|
|
3922
3976
|
content: [
|
|
3923
3977
|
`Article title: ${options.articleTitle}`,
|
|
3924
3978
|
`Article description: ${options.articleDescription}`,
|
|
3925
|
-
`
|
|
3926
|
-
`Expression to link: ${options.expression}`,
|
|
3979
|
+
`Text to add link to (input text): "${options.expression}"`,
|
|
3927
3980
|
"",
|
|
3928
3981
|
"Paragraph context:",
|
|
3929
3982
|
options.paragraph,
|
|
3930
3983
|
"",
|
|
3931
3984
|
"Search the web and choose the best URL for this inline link in this context.",
|
|
3932
|
-
"Use the exact expression first, then only accept close canonical variants when meaning is unchanged.",
|
|
3933
|
-
'If search evidence does not clearly support this expression in this paragraph context, return "none".',
|
|
3934
3985
|
'Output format: URL only, or "none".'
|
|
3935
3986
|
].join("\n")
|
|
3936
3987
|
}
|
|
@@ -7688,6 +7739,76 @@ function withWriteResumeHint(message) {
|
|
|
7688
7739
|
return `${trimmed} ${WRITE_RESUME_HINT}`;
|
|
7689
7740
|
}
|
|
7690
7741
|
|
|
7742
|
+
// src/cli/notifications/osNotifier.ts
|
|
7743
|
+
import { spawn as spawn2 } from "child_process";
|
|
7744
|
+
var APP_NAME = "Ideon";
|
|
7745
|
+
var MAX_MESSAGE_LENGTH = 180;
|
|
7746
|
+
async function notifyWriteStarted(params) {
|
|
7747
|
+
if (!params.enabled) {
|
|
7748
|
+
return;
|
|
7749
|
+
}
|
|
7750
|
+
const title = params.runMode === "resume" ? `${APP_NAME}: Resumed article write` : `${APP_NAME}: Started article write`;
|
|
7751
|
+
const message = truncateMessage(params.idea);
|
|
7752
|
+
sendOsNotification(title, message);
|
|
7753
|
+
}
|
|
7754
|
+
async function notifyWriteSucceeded(params) {
|
|
7755
|
+
if (!params.enabled) {
|
|
7756
|
+
return;
|
|
7757
|
+
}
|
|
7758
|
+
const title = `${APP_NAME}: Article ready`;
|
|
7759
|
+
const message = truncateMessage(`${params.title} (${params.slug})`);
|
|
7760
|
+
sendOsNotification(title, message);
|
|
7761
|
+
}
|
|
7762
|
+
async function notifyWriteFailed(params) {
|
|
7763
|
+
if (!params.enabled) {
|
|
7764
|
+
return;
|
|
7765
|
+
}
|
|
7766
|
+
const title = `${APP_NAME}: Article write failed`;
|
|
7767
|
+
const message = truncateMessage(params.message);
|
|
7768
|
+
sendOsNotification(title, message);
|
|
7769
|
+
}
|
|
7770
|
+
async function notifyWriteCanceled(params) {
|
|
7771
|
+
if (!params.enabled) {
|
|
7772
|
+
return;
|
|
7773
|
+
}
|
|
7774
|
+
const title = `${APP_NAME}: Article write canceled`;
|
|
7775
|
+
const message = truncateMessage(`Interrupted by ${params.signal}.`);
|
|
7776
|
+
sendOsNotification(title, message);
|
|
7777
|
+
}
|
|
7778
|
+
function sendOsNotification(title, message) {
|
|
7779
|
+
if (process.platform === "darwin") {
|
|
7780
|
+
const escapedTitle = escapeAppleScript(title);
|
|
7781
|
+
const escapedMessage = escapeAppleScript(message);
|
|
7782
|
+
runCommand("osascript", ["-e", `display notification "${escapedMessage}" with title "${escapedTitle}"`]);
|
|
7783
|
+
return;
|
|
7784
|
+
}
|
|
7785
|
+
if (process.platform === "linux") {
|
|
7786
|
+
runCommand("notify-send", [title, message]);
|
|
7787
|
+
}
|
|
7788
|
+
}
|
|
7789
|
+
function runCommand(command, args) {
|
|
7790
|
+
try {
|
|
7791
|
+
const child = spawn2(command, args, {
|
|
7792
|
+
stdio: "ignore",
|
|
7793
|
+
windowsHide: true
|
|
7794
|
+
});
|
|
7795
|
+
child.on("error", () => {
|
|
7796
|
+
});
|
|
7797
|
+
child.unref();
|
|
7798
|
+
} catch {
|
|
7799
|
+
}
|
|
7800
|
+
}
|
|
7801
|
+
function escapeAppleScript(value2) {
|
|
7802
|
+
return value2.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
7803
|
+
}
|
|
7804
|
+
function truncateMessage(value2) {
|
|
7805
|
+
const normalized = value2.trim();
|
|
7806
|
+
if (normalized.length <= MAX_MESSAGE_LENGTH) {
|
|
7807
|
+
return normalized;
|
|
7808
|
+
}
|
|
7809
|
+
return `${normalized.slice(0, MAX_MESSAGE_LENGTH - 3)}...`;
|
|
7810
|
+
}
|
|
7811
|
+
|
|
7691
7812
|
// src/cli/logging/plainRenderer.ts
|
|
7692
7813
|
function formatDuration2(durationMs) {
|
|
7693
7814
|
if (durationMs >= 1e3) {
|
|
@@ -7735,7 +7856,13 @@ function formatCost2(costUsd) {
|
|
|
7735
7856
|
async function renderPlainPipeline(input, dryRun, enrichLinks2, runMode) {
|
|
7736
7857
|
let previousStatuses = /* @__PURE__ */ new Map();
|
|
7737
7858
|
let previousItemStatuses = /* @__PURE__ */ new Map();
|
|
7859
|
+
const notificationsEnabled = input.config.settings.notifications.enabled;
|
|
7738
7860
|
try {
|
|
7861
|
+
await notifyWriteStarted({
|
|
7862
|
+
enabled: notificationsEnabled,
|
|
7863
|
+
idea: input.idea,
|
|
7864
|
+
runMode
|
|
7865
|
+
});
|
|
7739
7866
|
const result = await runPipelineShell(input, {
|
|
7740
7867
|
dryRun,
|
|
7741
7868
|
enrichLinks: enrichLinks2,
|
|
@@ -7771,8 +7898,17 @@ async function renderPlainPipeline(input, dryRun, enrichLinks2, runMode) {
|
|
|
7771
7898
|
console.log(` duration_ms: ${result.analytics.summary.totalDurationMs}`);
|
|
7772
7899
|
console.log(` retries: ${result.analytics.summary.totalRetries}`);
|
|
7773
7900
|
console.log(` cost: ${formatCost2(result.analytics.summary.totalCostUsd)}`);
|
|
7901
|
+
await notifyWriteSucceeded({
|
|
7902
|
+
enabled: notificationsEnabled,
|
|
7903
|
+
title: result.artifact.title,
|
|
7904
|
+
slug: result.artifact.slug
|
|
7905
|
+
});
|
|
7774
7906
|
} catch (error) {
|
|
7775
7907
|
const message = error instanceof Error ? withWriteResumeHint(error.message) : withWriteResumeHint("Pipeline failed.");
|
|
7908
|
+
await notifyWriteFailed({
|
|
7909
|
+
enabled: notificationsEnabled,
|
|
7910
|
+
message
|
|
7911
|
+
});
|
|
7776
7912
|
console.error(`Pipeline failed: ${message}`);
|
|
7777
7913
|
throw new ReportedError(message);
|
|
7778
7914
|
}
|
|
@@ -8115,6 +8251,11 @@ function WriteApp({
|
|
|
8115
8251
|
let mounted = true;
|
|
8116
8252
|
void (async () => {
|
|
8117
8253
|
try {
|
|
8254
|
+
await notifyWriteStarted({
|
|
8255
|
+
enabled: input.config.settings.notifications.enabled,
|
|
8256
|
+
idea: input.idea,
|
|
8257
|
+
runMode
|
|
8258
|
+
});
|
|
8118
8259
|
const runResult = await runPipelineShell(input, {
|
|
8119
8260
|
dryRun,
|
|
8120
8261
|
enrichLinks: enrichLinks2,
|
|
@@ -8129,6 +8270,11 @@ function WriteApp({
|
|
|
8129
8270
|
return;
|
|
8130
8271
|
}
|
|
8131
8272
|
setResult(runResult);
|
|
8273
|
+
await notifyWriteSucceeded({
|
|
8274
|
+
enabled: input.config.settings.notifications.enabled,
|
|
8275
|
+
title: runResult.artifact.title,
|
|
8276
|
+
slug: runResult.artifact.slug
|
|
8277
|
+
});
|
|
8132
8278
|
} catch (error) {
|
|
8133
8279
|
if (!mounted) {
|
|
8134
8280
|
return;
|
|
@@ -8137,6 +8283,10 @@ function WriteApp({
|
|
|
8137
8283
|
const messageWithResumeHint = withWriteResumeHint(normalizedError.message);
|
|
8138
8284
|
setErrorMessage(messageWithResumeHint);
|
|
8139
8285
|
onError(new Error(messageWithResumeHint));
|
|
8286
|
+
await notifyWriteFailed({
|
|
8287
|
+
enabled: input.config.settings.notifications.enabled,
|
|
8288
|
+
message: messageWithResumeHint
|
|
8289
|
+
});
|
|
8140
8290
|
}
|
|
8141
8291
|
})();
|
|
8142
8292
|
return () => {
|
|
@@ -8191,6 +8341,10 @@ async function runWritePipeline(input, dryRun, enrichLinks2, runMode) {
|
|
|
8191
8341
|
interruptHandled = true;
|
|
8192
8342
|
void (async () => {
|
|
8193
8343
|
try {
|
|
8344
|
+
await notifyWriteCanceled({
|
|
8345
|
+
enabled: input.config.settings.notifications.enabled,
|
|
8346
|
+
signal
|
|
8347
|
+
});
|
|
8194
8348
|
await recordInterruptedWrite(signal);
|
|
8195
8349
|
} finally {
|
|
8196
8350
|
cleanupSignalHandlers();
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@telepat/ideon",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "CLI for generating rich articles and images from ideas.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
8
8
|
"url": "git+https://github.com/telepat-io/ideon.git"
|
|
9
9
|
},
|
|
10
|
-
"homepage": "https://telepat
|
|
10
|
+
"homepage": "https://docs.telepat.io/ideon",
|
|
11
11
|
"bugs": {
|
|
12
12
|
"url": "https://github.com/telepat-io/ideon/issues"
|
|
13
13
|
},
|