@bastani/atomic 0.8.1 → 0.8.2
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/CHANGELOG.md +12 -0
- package/dist/builtin/intercom/config.ts +3 -4
- package/dist/builtin/intercom/index.ts +6 -6
- package/dist/builtin/intercom/package.json +1 -1
- package/dist/builtin/mcp/agent-dir.ts +11 -2
- package/dist/builtin/mcp/cli.js +12 -6
- package/dist/builtin/mcp/config.ts +31 -22
- package/dist/builtin/mcp/package.json +1 -1
- package/dist/builtin/subagents/package.json +1 -1
- package/dist/builtin/subagents/src/agents/agents.ts +63 -23
- package/dist/builtin/subagents/src/agents/skills.ts +21 -21
- package/dist/builtin/subagents/src/extension/index.ts +9 -8
- package/dist/builtin/subagents/src/runs/shared/run-history.ts +13 -10
- package/dist/builtin/subagents/src/runs/shared/subagent-prompt-runtime.ts +3 -3
- package/dist/builtin/subagents/src/shared/artifacts.ts +18 -17
- package/dist/builtin/subagents/src/shared/types.ts +4 -4
- package/dist/builtin/web-access/config-paths.ts +11 -0
- package/dist/builtin/web-access/exa.ts +3 -2
- package/dist/builtin/web-access/gemini-api.ts +2 -1
- package/dist/builtin/web-access/gemini-search.ts +2 -1
- package/dist/builtin/web-access/gemini-web-config.ts +2 -1
- package/dist/builtin/web-access/github-extract.ts +2 -1
- package/dist/builtin/web-access/index.ts +11 -8
- package/dist/builtin/web-access/package.json +1 -1
- package/dist/builtin/web-access/perplexity.ts +2 -1
- package/dist/builtin/web-access/video-extract.ts +2 -1
- package/dist/builtin/web-access/youtube-extract.ts +2 -1
- package/dist/builtin/workflows/builtin/deep-research-codebase.ts +4 -0
- package/dist/builtin/workflows/builtin/open-claude-design.ts +39 -22
- package/dist/builtin/workflows/builtin/ralph.ts +7 -0
- package/dist/builtin/workflows/package.json +1 -1
- package/dist/builtin/workflows/skills/workflow/SKILL.md +28 -20
- package/dist/builtin/workflows/skills/workflow/references/design-checklist.md +8 -4
- package/dist/builtin/workflows/skills/workflow/references/running-workflows.md +52 -23
- package/dist/builtin/workflows/skills/workflow/references/sdk-authoring.md +41 -12
- package/dist/builtin/workflows/src/extension/config-loader.ts +13 -14
- package/dist/builtin/workflows/src/extension/discovery.ts +4 -6
- package/dist/builtin/workflows/src/extension/index.ts +675 -524
- package/dist/builtin/workflows/src/extension/runtime.ts +40 -16
- package/dist/builtin/workflows/src/extension/wiring.ts +3 -0
- package/dist/builtin/workflows/src/extension/workflow-schema.ts +43 -33
- package/dist/builtin/workflows/src/runs/foreground/executor.ts +34 -10
- package/dist/builtin/workflows/src/shared/types.ts +1 -5
- package/dist/builtin/workflows/src/tui/graph-view.ts +245 -75
- package/dist/builtin/workflows/src/tui/overlay-adapter.ts +23 -0
- package/dist/builtin/workflows/src/tui/stage-chat-view.ts +259 -149
- package/dist/builtin/workflows/src/tui/status-helpers.ts +3 -3
- package/dist/builtin/workflows/src/tui/store-widget-installer.ts +99 -10
- package/dist/builtin/workflows/src/tui/switcher.ts +4 -5
- package/dist/builtin/workflows/src/tui/workflow-attach-pane.ts +29 -0
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +11 -8
- package/dist/cli/args.js.map +1 -1
- package/dist/config.d.ts +21 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +59 -4
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session.d.ts +1 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +2 -2
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/auth-storage.d.ts +3 -1
- package/dist/core/auth-storage.d.ts.map +1 -1
- package/dist/core/auth-storage.js +31 -8
- package/dist/core/auth-storage.js.map +1 -1
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +9 -0
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +11 -0
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/model-registry.d.ts +3 -2
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +25 -8
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/package-manager.d.ts +3 -0
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js +97 -58
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/resource-loader.d.ts +1 -0
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +37 -36
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/sdk.d.ts +5 -4
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +2 -2
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/settings-manager.d.ts +7 -1
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +29 -8
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/system-prompt.d.ts +1 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/telemetry.d.ts.map +1 -1
- package/dist/core/telemetry.js +2 -2
- package/dist/core/telemetry.js.map +1 -1
- package/dist/core/timings.d.ts.map +1 -1
- package/dist/core/timings.js +2 -2
- package/dist/core/timings.js.map +1 -1
- package/dist/core/tools/index.d.ts +1 -0
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/index.js +8 -0
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/todos.d.ts.map +1 -1
- package/dist/core/tools/todos.js +3 -3
- package/dist/core/tools/todos.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +6 -6
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/atomic-banner.d.ts +4 -0
- package/dist/modes/interactive/components/atomic-banner.d.ts.map +1 -0
- package/dist/modes/interactive/components/atomic-banner.js +34 -0
- package/dist/modes/interactive/components/atomic-banner.js.map +1 -0
- package/dist/modes/interactive/components/chat-message-renderer.d.ts +99 -0
- package/dist/modes/interactive/components/chat-message-renderer.d.ts.map +1 -0
- package/dist/modes/interactive/components/chat-message-renderer.js +450 -0
- package/dist/modes/interactive/components/chat-message-renderer.js.map +1 -0
- package/dist/modes/interactive/components/chat-transcript.d.ts +69 -0
- package/dist/modes/interactive/components/chat-transcript.d.ts.map +1 -0
- package/dist/modes/interactive/components/chat-transcript.js +183 -0
- package/dist/modes/interactive/components/chat-transcript.js.map +1 -0
- package/dist/modes/interactive/components/footer.d.ts +16 -4
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +110 -137
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/index.d.ts +2 -0
- package/dist/modes/interactive/components/index.d.ts.map +1 -1
- package/dist/modes/interactive/components/index.js +2 -0
- package/dist/modes/interactive/components/index.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +9 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +192 -137
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/theme/catppuccin-mocha.json +5 -5
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +11 -0
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/utils/tools-manager.d.ts.map +1 -1
- package/dist/utils/tools-manager.js +2 -2
- package/dist/utils/tools-manager.js.map +1 -1
- package/dist/utils/version-check.d.ts.map +1 -1
- package/dist/utils/version-check.js +2 -2
- package/dist/utils/version-check.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import * as os from "node:os";
|
|
3
3
|
import * as path from "node:path";
|
|
4
|
-
import {
|
|
4
|
+
import { getAgentConfigPaths } from "@bastani/atomic";
|
|
5
5
|
import { TEMP_ARTIFACTS_DIR, type ArtifactPaths } from "./types.ts";
|
|
6
6
|
const CLEANUP_MARKER_FILE = ".last-cleanup";
|
|
7
7
|
|
|
@@ -75,25 +75,26 @@ export function cleanupOldArtifacts(dir: string, maxAgeDays: number): void {
|
|
|
75
75
|
export function cleanupAllArtifactDirs(maxAgeDays: number): void {
|
|
76
76
|
cleanupOldArtifacts(TEMP_ARTIFACTS_DIR, maxAgeDays);
|
|
77
77
|
|
|
78
|
-
const sessionsBase
|
|
79
|
-
|
|
78
|
+
for (const sessionsBase of getAgentConfigPaths("sessions")) {
|
|
79
|
+
if (!fs.existsSync(sessionsBase)) continue;
|
|
80
80
|
|
|
81
|
-
|
|
82
|
-
try {
|
|
83
|
-
dirs = fs.readdirSync(sessionsBase);
|
|
84
|
-
} catch {
|
|
85
|
-
// Session artifact cleanup is best-effort. If the sessions root cannot be read,
|
|
86
|
-
// skip cleanup instead of failing extension startup.
|
|
87
|
-
return;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
for (const dir of dirs) {
|
|
91
|
-
const artifactsDir = path.join(sessionsBase, dir, "subagent-artifacts");
|
|
81
|
+
let dirs: string[];
|
|
92
82
|
try {
|
|
93
|
-
|
|
83
|
+
dirs = fs.readdirSync(sessionsBase);
|
|
94
84
|
} catch {
|
|
95
|
-
// Session cleanup is best-effort.
|
|
96
|
-
//
|
|
85
|
+
// Session artifact cleanup is best-effort. If the sessions root cannot be read,
|
|
86
|
+
// skip cleanup instead of failing extension startup.
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
for (const dir of dirs) {
|
|
91
|
+
const artifactsDir = path.join(sessionsBase, dir, "subagent-artifacts");
|
|
92
|
+
try {
|
|
93
|
+
cleanupOldArtifacts(artifactsDir, maxAgeDays);
|
|
94
|
+
} catch {
|
|
95
|
+
// Session cleanup is best-effort. Keep going so one unreadable session dir
|
|
96
|
+
// does not block cleanup for the rest.
|
|
97
|
+
}
|
|
97
98
|
}
|
|
98
99
|
}
|
|
99
100
|
}
|
|
@@ -7,7 +7,7 @@ import * as path from "node:path";
|
|
|
7
7
|
import type { Message } from "@earendil-works/pi-ai";
|
|
8
8
|
import type { FSWatcher } from "node:fs";
|
|
9
9
|
import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
10
|
-
import { APP_NAME } from "@bastani/atomic";
|
|
10
|
+
import { APP_NAME, getEnvValue } from "@bastani/atomic";
|
|
11
11
|
|
|
12
12
|
const ENV_PREFIX = APP_NAME.toUpperCase();
|
|
13
13
|
const SUBAGENT_MAX_DEPTH_ENV = `${ENV_PREFIX}_SUBAGENT_MAX_DEPTH`;
|
|
@@ -650,7 +650,7 @@ export function normalizeMaxSubagentDepth(value: unknown): number | undefined {
|
|
|
650
650
|
}
|
|
651
651
|
|
|
652
652
|
export function resolveCurrentMaxSubagentDepth(configMaxDepth?: number): number {
|
|
653
|
-
return normalizeMaxSubagentDepth(
|
|
653
|
+
return normalizeMaxSubagentDepth(getEnvValue(SUBAGENT_MAX_DEPTH_ENV))
|
|
654
654
|
?? normalizeMaxSubagentDepth(configMaxDepth)
|
|
655
655
|
?? DEFAULT_SUBAGENT_MAX_DEPTH;
|
|
656
656
|
}
|
|
@@ -662,14 +662,14 @@ export function resolveChildMaxSubagentDepth(parentMaxDepth: number, agentMaxDep
|
|
|
662
662
|
}
|
|
663
663
|
|
|
664
664
|
export function checkSubagentDepth(configMaxDepth?: number): { blocked: boolean; depth: number; maxDepth: number } {
|
|
665
|
-
const depth = Number(
|
|
665
|
+
const depth = Number(getEnvValue(SUBAGENT_DEPTH_ENV) ?? "0");
|
|
666
666
|
const maxDepth = resolveCurrentMaxSubagentDepth(configMaxDepth);
|
|
667
667
|
const blocked = Number.isFinite(depth) && depth >= maxDepth;
|
|
668
668
|
return { blocked, depth, maxDepth };
|
|
669
669
|
}
|
|
670
670
|
|
|
671
671
|
export function getSubagentDepthEnv(maxDepth?: number): Record<string, string> {
|
|
672
|
-
const parentDepth = Number(
|
|
672
|
+
const parentDepth = Number(getEnvValue(SUBAGENT_DEPTH_ENV) ?? "0");
|
|
673
673
|
const nextDepth = Number.isFinite(parentDepth) ? parentDepth + 1 : 1;
|
|
674
674
|
return {
|
|
675
675
|
[SUBAGENT_DEPTH_ENV]: String(nextDepth),
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { getUserConfigPaths } from "@bastani/atomic";
|
|
3
|
+
|
|
4
|
+
export const WEB_SEARCH_CONFIG_PATHS = getUserConfigPaths("web-search.json");
|
|
5
|
+
export const WEB_SEARCH_CONFIG_PATH = WEB_SEARCH_CONFIG_PATHS[0] ?? "~/.atomic/web-search.json";
|
|
6
|
+
export const EXA_USAGE_PATHS = getUserConfigPaths("exa-usage.json");
|
|
7
|
+
export const EXA_USAGE_PATH = EXA_USAGE_PATHS[0] ?? "~/.atomic/exa-usage.json";
|
|
8
|
+
|
|
9
|
+
export function findReadableConfigPath(paths = WEB_SEARCH_CONFIG_PATHS): string {
|
|
10
|
+
return paths.find((path) => existsSync(path)) ?? paths[0] ?? WEB_SEARCH_CONFIG_PATH;
|
|
11
|
+
}
|
|
@@ -2,6 +2,7 @@ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { CONFIG_DIR_NAME } from "@bastani/atomic";
|
|
5
|
+
import { EXA_USAGE_PATH, findReadableConfigPath } from "./config-paths.ts";
|
|
5
6
|
import { activityMonitor } from "./activity.js";
|
|
6
7
|
import type { ExtractedContent } from "./extract.js";
|
|
7
8
|
import type { SearchOptions, SearchResponse } from "./perplexity.js";
|
|
@@ -9,8 +10,8 @@ import type { SearchOptions, SearchResponse } from "./perplexity.js";
|
|
|
9
10
|
const EXA_ANSWER_URL = "https://api.exa.ai/answer";
|
|
10
11
|
const EXA_SEARCH_URL = "https://api.exa.ai/search";
|
|
11
12
|
const EXA_MCP_URL = "https://mcp.exa.ai/mcp";
|
|
12
|
-
const CONFIG_PATH =
|
|
13
|
-
const USAGE_PATH =
|
|
13
|
+
const CONFIG_PATH = findReadableConfigPath();
|
|
14
|
+
const USAGE_PATH = EXA_USAGE_PATH;
|
|
14
15
|
|
|
15
16
|
const MONTHLY_LIMIT = 1000;
|
|
16
17
|
const WARNING_THRESHOLD = 800;
|
|
@@ -2,9 +2,10 @@ import { existsSync, readFileSync } from "node:fs";
|
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { CONFIG_DIR_NAME } from "@bastani/atomic";
|
|
5
|
+
import { findReadableConfigPath } from "./config-paths.ts";
|
|
5
6
|
|
|
6
7
|
export const API_BASE = "https://generativelanguage.googleapis.com/v1beta";
|
|
7
|
-
const CONFIG_PATH =
|
|
8
|
+
const CONFIG_PATH = findReadableConfigPath();
|
|
8
9
|
export const DEFAULT_MODEL = "gemini-3-flash-preview";
|
|
9
10
|
|
|
10
11
|
interface GeminiApiConfig {
|
|
@@ -7,6 +7,7 @@ import { getApiKey, API_BASE, DEFAULT_MODEL } from "./gemini-api.js";
|
|
|
7
7
|
import { isGeminiWebAvailable, queryWithCookies } from "./gemini-web.js";
|
|
8
8
|
import { isPerplexityAvailable, searchWithPerplexity, type SearchResult, type SearchResponse, type SearchOptions } from "./perplexity.js";
|
|
9
9
|
import { hasExaApiKey, isExaAvailable, searchWithExa } from "./exa.js";
|
|
10
|
+
import { findReadableConfigPath } from "./config-paths.ts";
|
|
10
11
|
|
|
11
12
|
export type SearchProvider = "auto" | "perplexity" | "gemini" | "exa";
|
|
12
13
|
export type ResolvedSearchProvider = Exclude<SearchProvider, "auto">;
|
|
@@ -15,7 +16,7 @@ export interface AttributedSearchResponse extends SearchResponse {
|
|
|
15
16
|
provider: ResolvedSearchProvider;
|
|
16
17
|
}
|
|
17
18
|
|
|
18
|
-
const CONFIG_PATH =
|
|
19
|
+
const CONFIG_PATH = findReadableConfigPath();
|
|
19
20
|
|
|
20
21
|
let cachedSearchConfig: { searchProvider: SearchProvider; searchModel?: string } | null = null;
|
|
21
22
|
|
|
@@ -2,8 +2,9 @@ import { existsSync, readFileSync } from "node:fs";
|
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { APP_NAME, CONFIG_DIR_NAME } from "@bastani/atomic";
|
|
5
|
+
import { findReadableConfigPath } from "./config-paths.ts";
|
|
5
6
|
|
|
6
|
-
const CONFIG_PATH =
|
|
7
|
+
const CONFIG_PATH = findReadableConfigPath();
|
|
7
8
|
const ALLOW_BROWSER_COOKIES_ENV = `${APP_NAME.toUpperCase()}_ALLOW_BROWSER_COOKIES`;
|
|
8
9
|
|
|
9
10
|
interface GeminiWebConfig {
|
|
@@ -6,8 +6,9 @@ import { CONFIG_DIR_NAME } from "@bastani/atomic";
|
|
|
6
6
|
import { activityMonitor } from "./activity.js";
|
|
7
7
|
import type { ExtractedContent } from "./extract.js";
|
|
8
8
|
import { checkGhAvailable, checkRepoSize, fetchViaApi, showGhHint } from "./github-api.js";
|
|
9
|
+
import { findReadableConfigPath } from "./config-paths.ts";
|
|
9
10
|
|
|
10
|
-
const CONFIG_PATH =
|
|
11
|
+
const CONFIG_PATH = findReadableConfigPath();
|
|
11
12
|
|
|
12
13
|
const BINARY_EXTENSIONS = new Set([
|
|
13
14
|
".png", ".jpg", ".jpeg", ".gif", ".bmp", ".ico", ".webp", ".svg", ".tiff", ".tif",
|
|
@@ -33,14 +33,16 @@ import { createRequire } from "node:module";
|
|
|
33
33
|
import { platform, homedir } from "node:os";
|
|
34
34
|
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs";
|
|
35
35
|
import { join } from "node:path";
|
|
36
|
-
import { CONFIG_DIR_NAME } from "@bastani/atomic";
|
|
36
|
+
import { CONFIG_DIR_NAME, getUserConfigPaths } from "@bastani/atomic";
|
|
37
|
+
import { findReadableConfigPath } from "./config-paths.ts";
|
|
37
38
|
import { isPerplexityAvailable } from "./perplexity.js";
|
|
38
39
|
import { isExaAvailable } from "./exa.js";
|
|
39
40
|
import { isGeminiApiAvailable } from "./gemini-api.js";
|
|
40
41
|
import { getActiveGoogleEmail, isGeminiWebAvailable } from "./gemini-web.js";
|
|
41
42
|
import { isBrowserCookieAccessAllowed } from "./gemini-web-config.ts";
|
|
42
43
|
|
|
43
|
-
const WEB_SEARCH_CONFIG_PATH = join(homedir(), CONFIG_DIR_NAME, "web-search.json");
|
|
44
|
+
const WEB_SEARCH_CONFIG_PATH = getUserConfigPaths("web-search.json")[0] ?? join(homedir(), CONFIG_DIR_NAME, "web-search.json");
|
|
45
|
+
const WEB_SEARCH_CONFIG_READ_PATH = findReadableConfigPath();
|
|
44
46
|
|
|
45
47
|
interface WebSearchConfig {
|
|
46
48
|
provider?: string;
|
|
@@ -69,25 +71,26 @@ interface CuratorBootstrap {
|
|
|
69
71
|
}
|
|
70
72
|
|
|
71
73
|
function loadConfig(): WebSearchConfig {
|
|
72
|
-
if (!existsSync(
|
|
73
|
-
const raw = readFileSync(
|
|
74
|
+
if (!existsSync(WEB_SEARCH_CONFIG_READ_PATH)) return {};
|
|
75
|
+
const raw = readFileSync(WEB_SEARCH_CONFIG_READ_PATH, "utf-8");
|
|
74
76
|
try {
|
|
75
77
|
return JSON.parse(raw) as WebSearchConfig;
|
|
76
78
|
} catch (err) {
|
|
77
79
|
const message = err instanceof Error ? err.message : String(err);
|
|
78
|
-
throw new Error(`Failed to parse ${
|
|
80
|
+
throw new Error(`Failed to parse ${WEB_SEARCH_CONFIG_READ_PATH}: ${message}`);
|
|
79
81
|
}
|
|
80
82
|
}
|
|
81
83
|
|
|
82
84
|
function saveConfig(updates: Partial<WebSearchConfig>): void {
|
|
83
85
|
let config: Record<string, unknown> = {};
|
|
84
|
-
|
|
85
|
-
|
|
86
|
+
const existingConfigPath = findReadableConfigPath();
|
|
87
|
+
if (existsSync(existingConfigPath)) {
|
|
88
|
+
const raw = readFileSync(existingConfigPath, "utf-8");
|
|
86
89
|
try {
|
|
87
90
|
config = JSON.parse(raw) as Record<string, unknown>;
|
|
88
91
|
} catch (err) {
|
|
89
92
|
const message = err instanceof Error ? err.message : String(err);
|
|
90
|
-
throw new Error(`Failed to parse ${
|
|
93
|
+
throw new Error(`Failed to parse ${existingConfigPath}: ${message}`);
|
|
91
94
|
}
|
|
92
95
|
}
|
|
93
96
|
|
|
@@ -4,9 +4,10 @@ import { join } from "node:path";
|
|
|
4
4
|
import { CONFIG_DIR_NAME } from "@bastani/atomic";
|
|
5
5
|
import { activityMonitor } from "./activity.js";
|
|
6
6
|
import type { ExtractedContent } from "./extract.js";
|
|
7
|
+
import { findReadableConfigPath } from "./config-paths.ts";
|
|
7
8
|
|
|
8
9
|
const PERPLEXITY_API_URL = "https://api.perplexity.ai/chat/completions";
|
|
9
|
-
const CONFIG_PATH =
|
|
10
|
+
const CONFIG_PATH = findReadableConfigPath();
|
|
10
11
|
|
|
11
12
|
const RATE_LIMIT = {
|
|
12
13
|
maxRequests: 10,
|
|
@@ -9,8 +9,9 @@ import { isGeminiWebAvailable, queryWithCookies } from "./gemini-web.js";
|
|
|
9
9
|
import { queryGeminiApiWithVideo, getApiKey, API_BASE } from "./gemini-api.js";
|
|
10
10
|
import { extractHeadingTitle, type ExtractedContent, type ExtractOptions, type FrameResult } from "./extract.js";
|
|
11
11
|
import { readExecError, trimErrorText, mapFfmpegError } from "./utils.js";
|
|
12
|
+
import { findReadableConfigPath } from "./config-paths.ts";
|
|
12
13
|
|
|
13
|
-
const CONFIG_PATH =
|
|
14
|
+
const CONFIG_PATH = findReadableConfigPath();
|
|
14
15
|
const UPLOAD_BASE = "https://generativelanguage.googleapis.com/upload/v1beta";
|
|
15
16
|
|
|
16
17
|
const DEFAULT_VIDEO_PROMPT = `Extract the complete content of this video. Include:
|
|
@@ -9,8 +9,9 @@ import { isGeminiApiAvailable, queryGeminiApiWithVideo } from "./gemini-api.js";
|
|
|
9
9
|
import { searchWithPerplexity } from "./perplexity.js";
|
|
10
10
|
import { extractHeadingTitle, type ExtractedContent, type FrameResult, type VideoFrame } from "./extract.js";
|
|
11
11
|
import { formatSeconds, readExecError, isTimeoutError, trimErrorText, mapFfmpegError } from "./utils.js";
|
|
12
|
+
import { findReadableConfigPath } from "./config-paths.ts";
|
|
12
13
|
|
|
13
|
-
const CONFIG_PATH =
|
|
14
|
+
const CONFIG_PATH = findReadableConfigPath();
|
|
14
15
|
|
|
15
16
|
const YOUTUBE_PROMPT = `Extract the complete content of this YouTube video. Include:
|
|
16
17
|
1. Video title, channel name, and duration
|
|
@@ -185,6 +185,8 @@ export default defineWorkflow("deep-research-codebase")
|
|
|
185
185
|
codebaseLines,
|
|
186
186
|
);
|
|
187
187
|
|
|
188
|
+
let noAskQuestionToolSet = ["read, bash, edit, write, todo"];
|
|
189
|
+
|
|
188
190
|
let plannerModelConfig = {
|
|
189
191
|
model: "openai/gpt-5.5",
|
|
190
192
|
fallbackModels: [
|
|
@@ -193,6 +195,7 @@ export default defineWorkflow("deep-research-codebase")
|
|
|
193
195
|
"github-copilot/claude-opus-4.7",
|
|
194
196
|
],
|
|
195
197
|
thinkingLevel: "high" as const,
|
|
198
|
+
tools: noAskQuestionToolSet,
|
|
196
199
|
};
|
|
197
200
|
|
|
198
201
|
let explorerModelConfig = {
|
|
@@ -203,6 +206,7 @@ export default defineWorkflow("deep-research-codebase")
|
|
|
203
206
|
"github-copilot/claude-haiku-4.5",
|
|
204
207
|
],
|
|
205
208
|
thinkingLevel: "low" as const,
|
|
209
|
+
tools: noAskQuestionToolSet,
|
|
206
210
|
};
|
|
207
211
|
|
|
208
212
|
const initialDiscovery = await ctx.parallel(
|
|
@@ -122,8 +122,8 @@ function prepareArtifactDir(): {
|
|
|
122
122
|
} {
|
|
123
123
|
const runId = `${new Date().toISOString().replace(/[:.]/g, "-")}-${Math.random().toString(36).slice(2, 8)}`;
|
|
124
124
|
const candidates = [
|
|
125
|
-
join(process.cwd(), "
|
|
126
|
-
join(tmpdir(), "
|
|
125
|
+
join(process.cwd(), "specs", "design", runId),
|
|
126
|
+
join(tmpdir(), "open-claude-design", runId),
|
|
127
127
|
];
|
|
128
128
|
for (const candidate of candidates) {
|
|
129
129
|
try {
|
|
@@ -164,6 +164,13 @@ const ANTI_SLOP_RULES = [
|
|
|
164
164
|
"Commit to a specific aesthetic direction; do not hedge with generic SaaS defaults.",
|
|
165
165
|
].join("\n");
|
|
166
166
|
|
|
167
|
+
const PLAYWRIGHT_BROWSER_BOOTSTRAP_RULES = [
|
|
168
|
+
"Probe for playwright-cli availability with `playwright-cli --version` (or `npx --no-install playwright-cli --version` when relying on a project-local install). Do not install playwright-cli itself.",
|
|
169
|
+
"If playwright-cli is available but opening a page fails because Chrome, Chrome for Testing, Chromium, or another browser executable is not installed, run `playwright-cli install-browser chrome-for-testing` (or the equivalent `npx --no-install playwright-cli install-browser chrome-for-testing`) and retry the browser action once.",
|
|
170
|
+
"Only install the missing browser runtime; do not install npm packages, change project dependencies, or repeatedly retry failed installs.",
|
|
171
|
+
"If playwright-cli is unavailable or browser installation still fails, degrade gracefully and surface the manual file path / URL.",
|
|
172
|
+
].join("\n");
|
|
173
|
+
|
|
167
174
|
export default defineWorkflow("open-claude-design")
|
|
168
175
|
.description(
|
|
169
176
|
"AI-powered design workflow: design-system onboarding → reference import → HTML generation → impeccable-driven refinement → quality gate → rich HTML handoff. Each stage delegates to a specific impeccable sub-skill; the user can iteratively review and annotate the generated HTML through playwright-cli.",
|
|
@@ -447,13 +454,15 @@ export default defineWorkflow("open-claude-design")
|
|
|
447
454
|
"impeccable_skill",
|
|
448
455
|
"extract — separate one-off styling from repeated, intentional patterns. Only carry forward what is used 3+ times or what is structurally load-bearing.",
|
|
449
456
|
],
|
|
457
|
+
["playwright_browser_bootstrap", PLAYWRIGHT_BROWSER_BOOTSTRAP_RULES],
|
|
450
458
|
[
|
|
451
459
|
"instructions",
|
|
452
460
|
[
|
|
453
461
|
"1. Use browser/screenshot tooling (e.g. playwright-cli) if available; cite observable evidence rather than guessing.",
|
|
454
|
-
"2.
|
|
455
|
-
"3.
|
|
456
|
-
"4.
|
|
462
|
+
"2. If playwright-cli is available but opening the reference URL reports a missing browser executable, install Chrome for Testing with the bootstrap command and retry once.",
|
|
463
|
+
"3. Analyze: layout, visual hierarchy, navigation, color, typography, spacing, states, interactions, responsive behavior.",
|
|
464
|
+
"4. Separate reference-specific styling from requirements that should transfer to this project's design system.",
|
|
465
|
+
"5. If the URL is inaccessible or browser bootstrap fails, state that and provide a best-effort fallback based only on available information — never fabricate observations.",
|
|
457
466
|
].join("\n"),
|
|
458
467
|
],
|
|
459
468
|
[
|
|
@@ -573,14 +582,16 @@ export default defineWorkflow("open-claude-design")
|
|
|
573
582
|
],
|
|
574
583
|
["preview_path", previewPath],
|
|
575
584
|
["preview_file_url", previewFileUrl],
|
|
585
|
+
["playwright_browser_bootstrap", PLAYWRIGHT_BROWSER_BOOTSTRAP_RULES],
|
|
576
586
|
[
|
|
577
587
|
"instructions",
|
|
578
588
|
[
|
|
579
|
-
"1. Probe for playwright-cli availability
|
|
580
|
-
`2. If available, run: \`playwright-cli open ${previewFileUrl}
|
|
581
|
-
"3.
|
|
582
|
-
|
|
583
|
-
|
|
589
|
+
"1. Probe for playwright-cli availability using the bootstrap rules above.",
|
|
590
|
+
`2. If available, run: \`playwright-cli open ${previewFileUrl}\`. If that reports a missing browser executable, install Chrome for Testing with the bootstrap command and retry once.`,
|
|
591
|
+
"3. Then run `playwright-cli show --annotate` so the user can draw boxes and leave notes directly on the live page.",
|
|
592
|
+
"4. Once the user finishes annotating, capture the returned annotated snapshot path / notes and surface them in your output.",
|
|
593
|
+
`5. If playwright-cli is NOT available or browser bootstrap fails, print a clear instruction block telling the user to open the file manually at: ${previewPath} (or via the URL ${previewFileUrl}).`,
|
|
594
|
+
"6. Never block the workflow on unavailable tooling; always exit with a non-empty status string.",
|
|
584
595
|
].join("\n"),
|
|
585
596
|
],
|
|
586
597
|
[
|
|
@@ -699,13 +710,15 @@ export default defineWorkflow("open-claude-design")
|
|
|
699
710
|
["preview_path", previewPath],
|
|
700
711
|
["preview_file_url", previewFileUrl],
|
|
701
712
|
["current_design_and_feedback", "{previous}"],
|
|
713
|
+
["playwright_browser_bootstrap", PLAYWRIGHT_BROWSER_BOOTSTRAP_RULES],
|
|
702
714
|
[
|
|
703
715
|
"instructions",
|
|
704
716
|
[
|
|
705
|
-
`1. Attempt rendering verification via playwright-cli: \`playwright-cli open ${previewFileUrl}
|
|
706
|
-
|
|
707
|
-
"3.
|
|
708
|
-
"4.
|
|
717
|
+
`1. Attempt rendering verification via playwright-cli: \`playwright-cli open ${previewFileUrl}\`. If that reports a missing browser executable, install Chrome for Testing with the bootstrap command and retry once.`,
|
|
718
|
+
`2. Then run \`playwright-cli resize 360 800\`, \`playwright-cli screenshot --filename=${join(artifactDir, `mobile-${iteration}.png`)}\`, \`playwright-cli resize 1440 900\`, \`playwright-cli screenshot --filename=${join(artifactDir, `desktop-${iteration}.png`)}\`.`,
|
|
719
|
+
"3. Check: contrast (WCAG AA), overflow, spacing rhythm, alignment, breakpoint behavior, empty/loading/error states, keyboard/pointer affordances, focus rings, prefers-reduced-motion.",
|
|
720
|
+
"4. If playwright-cli is unavailable or browser bootstrap fails, perform a static design review of the HTML source and mark every finding as `needs-rendering-verification`.",
|
|
721
|
+
"5. Distinguish confirmed visual issues from risks that need rendering verification. Never fabricate rendered evidence.",
|
|
709
722
|
].join("\n"),
|
|
710
723
|
],
|
|
711
724
|
[
|
|
@@ -785,13 +798,15 @@ export default defineWorkflow("open-claude-design")
|
|
|
785
798
|
],
|
|
786
799
|
["preview_path", previewPath],
|
|
787
800
|
["preview_file_url", previewFileUrl],
|
|
801
|
+
["playwright_browser_bootstrap", PLAYWRIGHT_BROWSER_BOOTSTRAP_RULES],
|
|
788
802
|
[
|
|
789
803
|
"instructions",
|
|
790
804
|
[
|
|
791
|
-
`1. If playwright-cli is available, run \`playwright-cli goto ${previewFileUrl}\` (or open if no session is active),
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
"4.
|
|
805
|
+
`1. If playwright-cli is available, run \`playwright-cli goto ${previewFileUrl}\` (or \`playwright-cli open ${previewFileUrl}\` if no session is active). If that reports a missing browser executable, install Chrome for Testing with the bootstrap command and retry once.`,
|
|
806
|
+
"2. Then run `playwright-cli show --annotate` to invite annotated feedback.",
|
|
807
|
+
`3. If playwright-cli is unavailable or browser bootstrap fails, surface the path clearly: ${previewPath} (URL: ${previewFileUrl}).`,
|
|
808
|
+
"4. Return any captured annotations as structured notes the next user-feedback step can read.",
|
|
809
|
+
"5. Do not block on unavailable tooling.",
|
|
795
810
|
].join("\n"),
|
|
796
811
|
],
|
|
797
812
|
[
|
|
@@ -948,13 +963,15 @@ export default defineWorkflow("open-claude-design")
|
|
|
948
963
|
["spec_file_url", specFileUrl],
|
|
949
964
|
["preview_path", previewPath],
|
|
950
965
|
["preview_file_url", previewFileUrl],
|
|
966
|
+
["playwright_browser_bootstrap", PLAYWRIGHT_BROWSER_BOOTSTRAP_RULES],
|
|
951
967
|
[
|
|
952
968
|
"instructions",
|
|
953
969
|
[
|
|
954
|
-
"1. Probe for playwright-cli
|
|
955
|
-
`2. If available, run \`playwright-cli open ${specFileUrl}
|
|
956
|
-
|
|
957
|
-
|
|
970
|
+
"1. Probe for playwright-cli availability using the bootstrap rules above.",
|
|
971
|
+
`2. If available, run \`playwright-cli open ${specFileUrl}\`. If that reports a missing browser executable, install Chrome for Testing with the bootstrap command and retry once.`,
|
|
972
|
+
"3. Then run `playwright-cli show --annotate` so the user can capture any final notes.",
|
|
973
|
+
`4. Always print, prominently, the absolute paths so the user can open them manually:\n - Final spec: ${specPath}\n - Approved preview: ${previewPath}`,
|
|
974
|
+
"5. Do not block the workflow; return a structured summary even if no tooling worked.",
|
|
958
975
|
].join("\n"),
|
|
959
976
|
],
|
|
960
977
|
[
|
|
@@ -152,6 +152,8 @@ export default defineWorkflow("ralph")
|
|
|
152
152
|
let approved = false;
|
|
153
153
|
let iterationsCompleted = 0;
|
|
154
154
|
|
|
155
|
+
let noAskQuestionToolSet = ["read, bash, edit, write, todo"];
|
|
156
|
+
|
|
155
157
|
let plannerModelConfig = {
|
|
156
158
|
model: "openai/gpt-5.5",
|
|
157
159
|
fallbackModels: [
|
|
@@ -160,6 +162,7 @@ export default defineWorkflow("ralph")
|
|
|
160
162
|
"github-copilot/claude-opus-4.7",
|
|
161
163
|
],
|
|
162
164
|
thinkingLevel: "high" as const,
|
|
165
|
+
tools: noAskQuestionToolSet,
|
|
163
166
|
};
|
|
164
167
|
|
|
165
168
|
let orchestratorModelConfig = {
|
|
@@ -170,6 +173,7 @@ export default defineWorkflow("ralph")
|
|
|
170
173
|
"github-copilot/claude-sonnet-4.6",
|
|
171
174
|
],
|
|
172
175
|
thinkingLevel: "medium" as const,
|
|
176
|
+
tools: noAskQuestionToolSet,
|
|
173
177
|
};
|
|
174
178
|
|
|
175
179
|
let simplifierModelConfig = {
|
|
@@ -180,6 +184,7 @@ export default defineWorkflow("ralph")
|
|
|
180
184
|
"github-copilot/claude-sonnet-4.6",
|
|
181
185
|
],
|
|
182
186
|
thinkingLevel: "medium" as const,
|
|
187
|
+
tools: noAskQuestionToolSet,
|
|
183
188
|
};
|
|
184
189
|
|
|
185
190
|
let reviewerModelConfig = {
|
|
@@ -190,6 +195,7 @@ export default defineWorkflow("ralph")
|
|
|
190
195
|
"github-copilot/claude-opus-4.7",
|
|
191
196
|
],
|
|
192
197
|
thinkingLevel: "high" as const,
|
|
198
|
+
tools: noAskQuestionToolSet,
|
|
193
199
|
};
|
|
194
200
|
|
|
195
201
|
let explorerModelConfig = {
|
|
@@ -200,6 +206,7 @@ export default defineWorkflow("ralph")
|
|
|
200
206
|
"github-copilot/claude-haiku-4.5",
|
|
201
207
|
],
|
|
202
208
|
thinkingLevel: "low" as const,
|
|
209
|
+
tools: noAskQuestionToolSet,
|
|
203
210
|
};
|
|
204
211
|
|
|
205
212
|
for (let iteration = 1; iteration <= maxLoops; iteration += 1) {
|