ima2-gen 1.1.21 → 1.1.23
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/README.md +44 -7
- package/bin/commands/video.js +14 -0
- package/bin/ima2.js +14 -4
- package/bin/lib/platform.js +34 -5
- package/docs/README.ko.md +43 -2
- package/lib/agentQueueWorker.js +6 -0
- package/lib/agentRuntime.js +3 -2
- package/lib/atomicWrite.js +14 -0
- package/lib/grokImageAdapter.js +6 -0
- package/lib/grokProxyLauncher.js +5 -3
- package/lib/grokVideoAdapter.js +1 -1
- package/lib/grokVideoPlannerPrompt.js +10 -0
- package/lib/inflight.js +1 -1
- package/lib/oauthLauncher.js +5 -0
- package/lib/videoFrameExtract.js +3 -3
- package/package.json +5 -7
- package/routes/capabilities.js +13 -0
- package/routes/edit.js +2 -1
- package/routes/generate.js +32 -6
- package/routes/health.js +4 -3
- package/routes/multimode.js +2 -1
- package/routes/video.js +35 -3
- package/server.js +29 -2
- package/skills/ima2/SKILL.md +48 -6
- package/ui/dist/.vite/manifest.json +12 -12
- package/ui/dist/assets/{AgentWorkspace-B_hq9CLg.js → AgentWorkspace-C21zqdTZ.js} +1 -1
- package/ui/dist/assets/{CardNewsWorkspace-wD12J7qk.js → CardNewsWorkspace-BN-ga1lG.js} +1 -1
- package/ui/dist/assets/{NodeCanvas-CI_wuPMf.js → NodeCanvas-BbMa4IhI.js} +1 -1
- package/ui/dist/assets/{PromptBuilderPanel-CUTujJUV.js → PromptBuilderPanel-DRwBJRDQ.js} +1 -1
- package/ui/dist/assets/{PromptImportDialog-CUi66jPK.js → PromptImportDialog-Dp85kHCq.js} +2 -2
- package/ui/dist/assets/{PromptImportDiscoverySection-Cm3vrjY4.js → PromptImportDiscoverySection-BE8Q8MLD.js} +1 -1
- package/ui/dist/assets/{PromptImportFolderSection-DOtWTD9n.js → PromptImportFolderSection-PtH5x0sc.js} +1 -1
- package/ui/dist/assets/{PromptLibraryPanel-BMjQegRa.js → PromptLibraryPanel-FnM9tHI9.js} +2 -2
- package/ui/dist/assets/SettingsWorkspace-MARPGyBL.js +1 -0
- package/ui/dist/assets/index-BAFI6htx.js +42 -0
- package/ui/dist/assets/{index-31uVIdt4.js → index-BSXxr_Bt.js} +1 -1
- package/ui/dist/assets/index-DS-ADE7U.css +1 -0
- package/ui/dist/index.html +2 -2
- package/bin/commands/annotate.ts +0 -119
- package/bin/commands/cancel.ts +0 -48
- package/bin/commands/canvas-versions.ts +0 -80
- package/bin/commands/capabilities.ts +0 -110
- package/bin/commands/cardnews.ts +0 -249
- package/bin/commands/comfy.ts +0 -54
- package/bin/commands/config.ts +0 -186
- package/bin/commands/defaults.ts +0 -192
- package/bin/commands/doctor.ts +0 -202
- package/bin/commands/edit.ts +0 -150
- package/bin/commands/gen.ts +0 -214
- package/bin/commands/grok.ts +0 -90
- package/bin/commands/history.ts +0 -146
- package/bin/commands/ls.ts +0 -64
- package/bin/commands/metadata.ts +0 -39
- package/bin/commands/multimode.ts +0 -196
- package/bin/commands/node.ts +0 -166
- package/bin/commands/observability.ts +0 -176
- package/bin/commands/ping.ts +0 -31
- package/bin/commands/prompt-sub/build.ts +0 -101
- package/bin/commands/prompt.ts +0 -492
- package/bin/commands/ps.ts +0 -81
- package/bin/commands/session.ts +0 -266
- package/bin/commands/show.ts +0 -72
- package/bin/commands/skill.ts +0 -70
- package/bin/commands/video.ts +0 -442
- package/bin/ima2.ts +0 -430
- package/bin/lib/args.ts +0 -92
- package/bin/lib/browser-id.ts +0 -16
- package/bin/lib/client.ts +0 -122
- package/bin/lib/config-store.ts +0 -120
- package/bin/lib/destructive-confirm.ts +0 -19
- package/bin/lib/doctor-checks.ts +0 -91
- package/bin/lib/error-hints.ts +0 -23
- package/bin/lib/files.ts +0 -39
- package/bin/lib/output.ts +0 -73
- package/bin/lib/platform.ts +0 -99
- package/bin/lib/recover-output.ts +0 -139
- package/bin/lib/sse.ts +0 -73
- package/bin/lib/star-prompt.ts +0 -97
- package/bin/lib/storage-doctor.ts +0 -39
- package/bin/lib/ui-build.ts +0 -85
- package/config.ts +0 -354
- package/lib/agentCommandParser.ts +0 -69
- package/lib/agentGenerationPlanner.ts +0 -273
- package/lib/agentQuestionResponder.ts +0 -266
- package/lib/agentQueueStore.ts +0 -270
- package/lib/agentQueueWorker.ts +0 -89
- package/lib/agentRuntime.ts +0 -604
- package/lib/agentSettings.ts +0 -72
- package/lib/agentStore.ts +0 -422
- package/lib/agentStoreRows.ts +0 -136
- package/lib/agentTypes.ts +0 -154
- package/lib/apiCachePolicy.ts +0 -11
- package/lib/assetLifecycle.ts +0 -146
- package/lib/canvasVersionStore.ts +0 -223
- package/lib/capabilities.ts +0 -126
- package/lib/cardNewsGenerator.ts +0 -271
- package/lib/cardNewsJobStore.ts +0 -142
- package/lib/cardNewsManifestStore.ts +0 -154
- package/lib/cardNewsPlanner.ts +0 -236
- package/lib/cardNewsPlannerClient.ts +0 -155
- package/lib/cardNewsPlannerPrompt.ts +0 -62
- package/lib/cardNewsPlannerSchema.ts +0 -321
- package/lib/cardNewsRoleTemplateStore.ts +0 -47
- package/lib/cardNewsTemplateStore.ts +0 -252
- package/lib/codexDetect.ts +0 -71
- package/lib/comfyBridge.ts +0 -235
- package/lib/composerSnapshot.ts +0 -33
- package/lib/configKeys.ts +0 -62
- package/lib/db.ts +0 -295
- package/lib/errInfo.ts +0 -43
- package/lib/errorClassify.ts +0 -100
- package/lib/generationCancel.ts +0 -28
- package/lib/generationErrors.ts +0 -238
- package/lib/grokImageAdapter.ts +0 -513
- package/lib/grokMultimodeAdapter.ts +0 -84
- package/lib/grokProxyLauncher.ts +0 -153
- package/lib/grokRuntime.ts +0 -23
- package/lib/grokSizeMapper.ts +0 -71
- package/lib/grokVideoAdapter.ts +0 -458
- package/lib/grokVideoCanvas.ts +0 -26
- package/lib/grokVideoDownload.ts +0 -59
- package/lib/grokVideoPlannerPrompt.ts +0 -67
- package/lib/historyIndex.ts +0 -51
- package/lib/historyList.ts +0 -181
- package/lib/imageMetadata.ts +0 -113
- package/lib/imageMetadataStore.ts +0 -67
- package/lib/imageModels.ts +0 -165
- package/lib/inflight.ts +0 -281
- package/lib/localImportStore.ts +0 -114
- package/lib/logger.ts +0 -161
- package/lib/nodeStore.ts +0 -91
- package/lib/oauthLauncher.ts +0 -94
- package/lib/oauthNormalize.ts +0 -30
- package/lib/oauthProxy/errors.ts +0 -128
- package/lib/oauthProxy/generators.ts +0 -494
- package/lib/oauthProxy/index.ts +0 -28
- package/lib/oauthProxy/prompts.ts +0 -123
- package/lib/oauthProxy/references.ts +0 -45
- package/lib/oauthProxy/runtime.ts +0 -115
- package/lib/oauthProxy/streams.ts +0 -232
- package/lib/oauthProxy/types.ts +0 -9
- package/lib/oauthProxy.ts +0 -3
- package/lib/openDirectory.ts +0 -47
- package/lib/pngInfo.ts +0 -26
- package/lib/promptBuilder/attachments.ts +0 -74
- package/lib/promptBuilder/client.ts +0 -130
- package/lib/promptBuilder/constants.ts +0 -9
- package/lib/promptBuilder/context.ts +0 -36
- package/lib/promptBuilder/errors.ts +0 -12
- package/lib/promptBuilder/requestSchema.ts +0 -56
- package/lib/promptBuilder/responseParser.ts +0 -219
- package/lib/promptBuilder/systemPrompt.ts +0 -135
- package/lib/promptBuilder/transport.ts +0 -94
- package/lib/promptBuilder/types.ts +0 -109
- package/lib/promptImport/curatedSources.ts +0 -141
- package/lib/promptImport/discoveryRegistry.ts +0 -329
- package/lib/promptImport/errors.ts +0 -18
- package/lib/promptImport/githubDiscovery.ts +0 -309
- package/lib/promptImport/githubFolder.ts +0 -397
- package/lib/promptImport/githubSource.ts +0 -257
- package/lib/promptImport/gptImageHints.ts +0 -70
- package/lib/promptImport/parsePromptCandidates.ts +0 -179
- package/lib/promptImport/promptIndex.ts +0 -326
- package/lib/promptImport/rankPromptCandidates.ts +0 -65
- package/lib/promptImport/types.ts +0 -103
- package/lib/promptSafetyPolicy.ts +0 -5
- package/lib/providerOptions.ts +0 -56
- package/lib/referenceImageCompress.ts +0 -84
- package/lib/refs.ts +0 -133
- package/lib/requestLogger.ts +0 -49
- package/lib/responsesDoctor.ts +0 -456
- package/lib/responsesErrors.ts +0 -83
- package/lib/responsesFallback.ts +0 -114
- package/lib/responsesImageAdapter.ts +0 -466
- package/lib/responsesParse.ts +0 -452
- package/lib/responsesTools.ts +0 -28
- package/lib/runtimeContext.ts +0 -146
- package/lib/runtimePorts.ts +0 -105
- package/lib/sessionStore.ts +0 -308
- package/lib/storageMigration.ts +0 -310
- package/lib/styleSheet.ts +0 -139
- package/lib/systemTrash.ts +0 -20
- package/lib/videoContinuity.ts +0 -180
- package/lib/videoFrameExtract.ts +0 -78
- package/lib/videoSeriesChain.ts +0 -29
- package/lib/visibleTextLanguagePolicy.ts +0 -7
- package/routes/agent.ts +0 -308
- package/routes/annotations.ts +0 -118
- package/routes/canvasVersions.ts +0 -69
- package/routes/capabilities.ts +0 -18
- package/routes/cardNews.ts +0 -211
- package/routes/comfy.ts +0 -43
- package/routes/edit.ts +0 -352
- package/routes/generate.ts +0 -492
- package/routes/grok.ts +0 -24
- package/routes/health.ts +0 -123
- package/routes/history.ts +0 -221
- package/routes/imageImport.ts +0 -37
- package/routes/index.ts +0 -52
- package/routes/metadata.ts +0 -77
- package/routes/multimode.ts +0 -499
- package/routes/nodes.ts +0 -578
- package/routes/promptBuilder.ts +0 -37
- package/routes/promptImport.ts +0 -379
- package/routes/prompts.ts +0 -428
- package/routes/quota.ts +0 -89
- package/routes/sessions.ts +0 -317
- package/routes/storage.ts +0 -47
- package/routes/video.ts +0 -300
- package/routes/videoExtended.ts +0 -284
- package/server.ts +0 -293
- package/ui/dist/assets/SettingsWorkspace-PiaVnsdA.js +0 -1
- package/ui/dist/assets/index-CjgnNtgt.css +0 -1
- package/ui/dist/assets/index-Da2s4_-5.js +0 -36
|
@@ -1,326 +0,0 @@
|
|
|
1
|
-
import { createHash } from "node:crypto";
|
|
2
|
-
import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
|
|
3
|
-
import { dirname } from "node:path";
|
|
4
|
-
import { getCuratedSource, getDefaultSearchSources, listCuratedSources } from "./curatedSources.js";
|
|
5
|
-
import { buildGitHubRawFileSource, fetchGitHubSource } from "./githubSource.js";
|
|
6
|
-
import { parsePromptCandidates } from "./parsePromptCandidates.js";
|
|
7
|
-
import { extractGptImageHints } from "./gptImageHints.js";
|
|
8
|
-
import { rankPromptCandidates } from "./rankPromptCandidates.js";
|
|
9
|
-
import { errInfo } from "../errInfo.js";
|
|
10
|
-
import { requireRuntimeContext } from "../runtimeContext.js";
|
|
11
|
-
import {
|
|
12
|
-
getDefaultReviewedDiscoverySources,
|
|
13
|
-
getReviewedDiscoverySource,
|
|
14
|
-
listReviewedDiscoverySources,
|
|
15
|
-
} from "./discoveryRegistry.js";
|
|
16
|
-
import type {
|
|
17
|
-
CuratedSourceLike,
|
|
18
|
-
GitHubFileSource,
|
|
19
|
-
PromptCandidate,
|
|
20
|
-
PromptImportCtx,
|
|
21
|
-
PromptImportLimits,
|
|
22
|
-
} from "./types.js";
|
|
23
|
-
|
|
24
|
-
const INDEX_VERSION = 1;
|
|
25
|
-
const EXTRACTOR_VERSION = 2;
|
|
26
|
-
|
|
27
|
-
interface IndexedFile {
|
|
28
|
-
sourceFileId: string;
|
|
29
|
-
owner: string | undefined;
|
|
30
|
-
repo: string;
|
|
31
|
-
ref: string;
|
|
32
|
-
path: string;
|
|
33
|
-
extension: string;
|
|
34
|
-
contentHash: string;
|
|
35
|
-
etag: string | null;
|
|
36
|
-
sizeBytes: number;
|
|
37
|
-
licenseSpdx: string;
|
|
38
|
-
htmlUrl: string;
|
|
39
|
-
indexedAt: string;
|
|
40
|
-
lastFetchStatus: string;
|
|
41
|
-
promptCandidateCount: number;
|
|
42
|
-
extractorVersion: number;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
interface IndexedCandidate extends PromptCandidate {
|
|
46
|
-
candidateId: string;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
interface CacheEntry {
|
|
50
|
-
source: CuratedSourceLike;
|
|
51
|
-
files: IndexedFile[];
|
|
52
|
-
candidates: IndexedCandidate[];
|
|
53
|
-
refreshedAt: number;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
interface IndexCache {
|
|
57
|
-
version: number;
|
|
58
|
-
sources: Record<string, CacheEntry>;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
interface IndexLimits extends PromptImportLimits {
|
|
62
|
-
searchLimit: number;
|
|
63
|
-
ttlMs: number;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
function limitsFromCtx(ctx: PromptImportCtx): IndexLimits {
|
|
67
|
-
const limits = (ctx.config?.limits ?? {}) as Record<string, number>;
|
|
68
|
-
return {
|
|
69
|
-
maxFileBytesForPreview: limits.promptImportMaxFileBytes,
|
|
70
|
-
maxPromptCandidatesPerFile: limits.promptImportMaxCandidatesPerFile,
|
|
71
|
-
maxPromptCandidatesPerImport: limits.promptImportMaxCandidatesPerImport,
|
|
72
|
-
fetchTimeoutMs: limits.promptImportFetchTimeoutMs,
|
|
73
|
-
maxCandidateChars: limits.promptImportMaxCandidateChars,
|
|
74
|
-
minCandidateChars: limits.promptImportMinCandidateChars,
|
|
75
|
-
maxSourceCharsScanned: limits.promptImportMaxSourceCharsScanned,
|
|
76
|
-
maxRepoIndexFiles: limits.promptImportMaxRepoIndexFiles,
|
|
77
|
-
maxFolderFiles: limits.promptImportMaxFolderFiles ?? 0,
|
|
78
|
-
maxFolderPreviewFiles: limits.promptImportMaxFolderPreviewFiles ?? 0,
|
|
79
|
-
searchLimit: limits.promptImportCuratedSearchLimit,
|
|
80
|
-
ttlMs: limits.promptImportIndexCacheTtlMs,
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
function cacheFile(ctx: PromptImportCtx): string {
|
|
85
|
-
const storage = (ctx.config as { storage?: { promptImportIndexCacheFile?: string } } | undefined)?.storage;
|
|
86
|
-
return storage?.promptImportIndexCacheFile ?? "";
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
function sourceFileId(source: CuratedSourceLike, path: string): string {
|
|
90
|
-
return `github:${source.repo}@${source.defaultRef}:${path}`;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
function hashId(...parts: string[]): string {
|
|
94
|
-
return createHash("sha256").update(parts.join("\0")).digest("hex");
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
async function readCache(ctx: PromptImportCtx): Promise<IndexCache> {
|
|
98
|
-
try {
|
|
99
|
-
const parsed = JSON.parse(await readFile(cacheFile(ctx), "utf8")) as IndexCache;
|
|
100
|
-
if (parsed.version !== INDEX_VERSION) return { version: INDEX_VERSION, sources: {} };
|
|
101
|
-
return { version: INDEX_VERSION, sources: parsed.sources || {} };
|
|
102
|
-
} catch {
|
|
103
|
-
return { version: INDEX_VERSION, sources: {} };
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
async function writeCache(ctx: PromptImportCtx, cache: IndexCache): Promise<void> {
|
|
108
|
-
const file = cacheFile(ctx);
|
|
109
|
-
await mkdir(dirname(file), { recursive: true });
|
|
110
|
-
const tmp = `${file}.${process.pid}.${Date.now()}.tmp`;
|
|
111
|
-
await writeFile(tmp, JSON.stringify(cache, null, 2));
|
|
112
|
-
await rename(tmp, file);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
function sourceTags(source: CuratedSourceLike, fileSource: GitHubFileSource): string[] {
|
|
116
|
-
return [
|
|
117
|
-
...(fileSource.tags ?? []),
|
|
118
|
-
`source:${source.id}`,
|
|
119
|
-
`license:${source.licenseSpdx}`,
|
|
120
|
-
`trust:${source.trustTier}`,
|
|
121
|
-
source.requiresAttribution ? "attribution-required" : null,
|
|
122
|
-
].filter(Boolean) as string[];
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
interface IndexedCandidateInput {
|
|
126
|
-
candidate: PromptCandidate;
|
|
127
|
-
source: CuratedSourceLike;
|
|
128
|
-
fileSource: GitHubFileSource;
|
|
129
|
-
fileIndex: IndexedFile;
|
|
130
|
-
index: number;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
function indexedCandidate({ candidate, source, fileSource, fileIndex, index }: IndexedCandidateInput): IndexedCandidate {
|
|
134
|
-
const scoreHints = extractGptImageHints(candidate.text);
|
|
135
|
-
const headingPath = candidate.headingPath || candidate.name || "";
|
|
136
|
-
const candidateId = hashId(fileIndex.sourceFileId, fileIndex.contentHash, headingPath, String(candidate.ordinal || index + 1));
|
|
137
|
-
const tags = [...new Set([...(candidate.tags || []), ...sourceTags(source, fileSource)])];
|
|
138
|
-
return {
|
|
139
|
-
...candidate,
|
|
140
|
-
id: candidateId,
|
|
141
|
-
candidateId,
|
|
142
|
-
name: candidate.name,
|
|
143
|
-
text: candidate.text,
|
|
144
|
-
textPreview: candidate.textPreview || candidate.text.slice(0, 220),
|
|
145
|
-
tags,
|
|
146
|
-
warnings: [...new Set([...(candidate.warnings || []), ...(scoreHints.warnings ?? [])])],
|
|
147
|
-
source: {
|
|
148
|
-
kind: "github",
|
|
149
|
-
owner: source.owner,
|
|
150
|
-
repo: source.name,
|
|
151
|
-
ref: source.defaultRef,
|
|
152
|
-
path: fileSource.path,
|
|
153
|
-
htmlUrl: fileSource.htmlUrl,
|
|
154
|
-
sourceId: source.id,
|
|
155
|
-
},
|
|
156
|
-
sourceFileId: fileIndex.sourceFileId,
|
|
157
|
-
headingPath,
|
|
158
|
-
ordinal: candidate.ordinal || index + 1,
|
|
159
|
-
promptHash: candidate.promptHash || hashId(candidate.text.trim().toLowerCase()),
|
|
160
|
-
scoreHints,
|
|
161
|
-
};
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
interface IndexSourceResult {
|
|
165
|
-
source: CuratedSourceLike | null | undefined;
|
|
166
|
-
indexedFiles: number;
|
|
167
|
-
candidateCount: number;
|
|
168
|
-
warnings: string[];
|
|
169
|
-
entry?: CacheEntry;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
async function indexSource(ctx: PromptImportCtx, sourceId: string): Promise<IndexSourceResult> {
|
|
173
|
-
const source = (getCuratedSource(sourceId) as CuratedSourceLike | undefined) || await getReviewedDiscoverySource(ctx, sourceId);
|
|
174
|
-
if (!source || source.trustTier === "manual-review") {
|
|
175
|
-
return { source, indexedFiles: 0, candidateCount: 0, warnings: ["curated-source-unavailable"] };
|
|
176
|
-
}
|
|
177
|
-
if (String(source.defaultRef || "").includes("/")) {
|
|
178
|
-
return { source, indexedFiles: 0, candidateCount: 0, warnings: ["discovery-default-branch-unsupported"] };
|
|
179
|
-
}
|
|
180
|
-
if (!Array.isArray(source.allowedPaths) || source.allowedPaths.length === 0) {
|
|
181
|
-
return { source, indexedFiles: 0, candidateCount: 0, warnings: ["discovery-requires-paths"] };
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
const limits = limitsFromCtx(ctx);
|
|
185
|
-
const warnings: string[] = [];
|
|
186
|
-
const files: IndexedFile[] = [];
|
|
187
|
-
const candidates: IndexedCandidate[] = [];
|
|
188
|
-
const allowedPaths = source.allowedPaths.slice(0, limits.maxRepoIndexFiles);
|
|
189
|
-
|
|
190
|
-
for (const path of allowedPaths) {
|
|
191
|
-
try {
|
|
192
|
-
const fileSource = buildGitHubRawFileSource({
|
|
193
|
-
owner: source.owner ?? "",
|
|
194
|
-
repo: source.name ?? source.repo,
|
|
195
|
-
ref: source.defaultRef,
|
|
196
|
-
path,
|
|
197
|
-
});
|
|
198
|
-
const fetched = await fetchGitHubSource(fileSource, limits);
|
|
199
|
-
const fileIndex: IndexedFile = {
|
|
200
|
-
sourceFileId: sourceFileId(source, path),
|
|
201
|
-
owner: source.owner,
|
|
202
|
-
repo: source.name ?? source.repo,
|
|
203
|
-
ref: source.defaultRef,
|
|
204
|
-
path,
|
|
205
|
-
extension: fileSource.extension ?? "",
|
|
206
|
-
contentHash: fetched.contentHash,
|
|
207
|
-
etag: fetched.etag,
|
|
208
|
-
sizeBytes: fetched.sizeBytes,
|
|
209
|
-
licenseSpdx: source.licenseSpdx,
|
|
210
|
-
htmlUrl: fileSource.htmlUrl ?? "",
|
|
211
|
-
indexedAt: new Date().toISOString(),
|
|
212
|
-
lastFetchStatus: "ok",
|
|
213
|
-
promptCandidateCount: 0,
|
|
214
|
-
extractorVersion: EXTRACTOR_VERSION,
|
|
215
|
-
};
|
|
216
|
-
const parsed = parsePromptCandidates({
|
|
217
|
-
text: fetched.text,
|
|
218
|
-
filename: path,
|
|
219
|
-
source: { kind: "github", owner: source.owner, repo: source.name, ref: source.defaultRef, path, htmlUrl: fileSource.htmlUrl },
|
|
220
|
-
tags: sourceTags(source, fileSource),
|
|
221
|
-
limits,
|
|
222
|
-
});
|
|
223
|
-
const indexed = parsed.map((candidate, index) => indexedCandidate({ candidate, source, fileSource, fileIndex, index }));
|
|
224
|
-
fileIndex.promptCandidateCount = indexed.length;
|
|
225
|
-
files.push(fileIndex);
|
|
226
|
-
candidates.push(...indexed);
|
|
227
|
-
} catch (error) {
|
|
228
|
-
const err = errInfo(error);
|
|
229
|
-
warnings.push(`${path}: ${err.message || "index failed"}`);
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
return {
|
|
234
|
-
source,
|
|
235
|
-
indexedFiles: files.length,
|
|
236
|
-
candidateCount: candidates.length,
|
|
237
|
-
warnings,
|
|
238
|
-
entry: {
|
|
239
|
-
source,
|
|
240
|
-
files,
|
|
241
|
-
candidates,
|
|
242
|
-
refreshedAt: Date.now(),
|
|
243
|
-
},
|
|
244
|
-
};
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
function isFresh(entry: CacheEntry | undefined, ttlMs: number): boolean {
|
|
248
|
-
return Boolean(entry?.refreshedAt && Date.now() - entry.refreshedAt < ttlMs);
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
async function ensureSearchCache(ctx: PromptImportCtx) {
|
|
252
|
-
const cache = await readCache(ctx);
|
|
253
|
-
const limits = limitsFromCtx(ctx);
|
|
254
|
-
const sources = [
|
|
255
|
-
...getDefaultSearchSources() as CuratedSourceLike[],
|
|
256
|
-
...await getDefaultReviewedDiscoverySources(ctx),
|
|
257
|
-
];
|
|
258
|
-
let changed = false;
|
|
259
|
-
const warnings: string[] = [];
|
|
260
|
-
|
|
261
|
-
for (const source of sources) {
|
|
262
|
-
if (isFresh(cache.sources[source.id], limits.ttlMs)) continue;
|
|
263
|
-
const result = await indexSource(ctx, source.id);
|
|
264
|
-
if (result.entry) {
|
|
265
|
-
cache.sources[source.id] = result.entry;
|
|
266
|
-
changed = true;
|
|
267
|
-
}
|
|
268
|
-
warnings.push(...result.warnings);
|
|
269
|
-
}
|
|
270
|
-
if (changed) await writeCache(ctx, cache);
|
|
271
|
-
return { cache, warnings };
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
export async function refreshCuratedSource(ctxIn: PromptImportCtx, sourceId: string) {
|
|
275
|
-
const ctx = requireRuntimeContext(ctxIn);
|
|
276
|
-
const cache = await readCache(ctx);
|
|
277
|
-
const result = await indexSource(ctx, sourceId);
|
|
278
|
-
if (result.entry) {
|
|
279
|
-
cache.sources[sourceId] = result.entry;
|
|
280
|
-
await writeCache(ctx, cache);
|
|
281
|
-
}
|
|
282
|
-
return {
|
|
283
|
-
source: result.source,
|
|
284
|
-
indexedFiles: result.indexedFiles,
|
|
285
|
-
candidateCount: result.candidateCount,
|
|
286
|
-
warnings: result.warnings,
|
|
287
|
-
};
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
interface SearchCuratedPromptsOptions {
|
|
291
|
-
q?: string;
|
|
292
|
-
sourceIds?: string[];
|
|
293
|
-
limit?: number;
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
export async function searchCuratedPrompts(ctxIn: PromptImportCtx, { q = "", sourceIds, limit }: SearchCuratedPromptsOptions = {}) {
|
|
297
|
-
const ctx = requireRuntimeContext(ctxIn);
|
|
298
|
-
const { cache, warnings } = await ensureSearchCache(ctx);
|
|
299
|
-
const limits = limitsFromCtx(ctx);
|
|
300
|
-
const defaultSources = [
|
|
301
|
-
...getDefaultSearchSources() as CuratedSourceLike[],
|
|
302
|
-
...await getDefaultReviewedDiscoverySources(ctx),
|
|
303
|
-
];
|
|
304
|
-
const allowedIds = Array.isArray(sourceIds) && sourceIds.length
|
|
305
|
-
? new Set(sourceIds)
|
|
306
|
-
: new Set(defaultSources.map((source) => source.id));
|
|
307
|
-
const candidates = Object.values(cache.sources)
|
|
308
|
-
.filter((entry) => allowedIds.has(entry.source.id))
|
|
309
|
-
.flatMap((entry) => entry.candidates || []);
|
|
310
|
-
const results = rankPromptCandidates({
|
|
311
|
-
candidates,
|
|
312
|
-
query: q,
|
|
313
|
-
limit: Math.min(Number(limit) || limits.searchLimit, limits.searchLimit),
|
|
314
|
-
});
|
|
315
|
-
const sources = [
|
|
316
|
-
...listCuratedSources(),
|
|
317
|
-
...await listReviewedDiscoverySources(ctx),
|
|
318
|
-
];
|
|
319
|
-
return { results, sources, warnings };
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
export async function getPromptImportSources(ctxIn: PromptImportCtx | null) {
|
|
323
|
-
const ctx = ctxIn ? requireRuntimeContext(ctxIn) : null;
|
|
324
|
-
const reviewed = ctx ? await listReviewedDiscoverySources(ctx) : [];
|
|
325
|
-
return { sources: [...listCuratedSources(), ...reviewed] };
|
|
326
|
-
}
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
import type { PromptCandidate } from "./types.js";
|
|
2
|
-
|
|
3
|
-
interface RankablePromptCandidate extends Partial<PromptCandidate> {
|
|
4
|
-
id: string;
|
|
5
|
-
name: string;
|
|
6
|
-
text: string;
|
|
7
|
-
sourceFileId?: string;
|
|
8
|
-
score?: number;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
interface RankPromptCandidatesOptions {
|
|
12
|
-
candidates: RankablePromptCandidate[];
|
|
13
|
-
query: string;
|
|
14
|
-
limit?: number;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
function tokenize(value: unknown): string[] {
|
|
18
|
-
return String(value || "")
|
|
19
|
-
.toLowerCase()
|
|
20
|
-
.split(/[^a-z0-9가-힣-]+/i)
|
|
21
|
-
.map((token) => token.trim())
|
|
22
|
-
.filter(Boolean);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function includesAny(values: unknown[], terms: string[]): boolean {
|
|
26
|
-
const haystack = values.map((value) => String(value || "").toLowerCase());
|
|
27
|
-
return terms.some((term) => haystack.some((value) => value.includes(term)));
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export function rankPromptCandidates({ candidates, query, limit }: RankPromptCandidatesOptions): RankablePromptCandidate[] {
|
|
31
|
-
const terms = tokenize(query);
|
|
32
|
-
const boundedLimit = Math.max(1, Math.min(Number(limit) || 50, 100));
|
|
33
|
-
const ranked = candidates.map((candidate) => {
|
|
34
|
-
const text = String(candidate.text || "").toLowerCase();
|
|
35
|
-
const name = String(candidate.name || "").toLowerCase();
|
|
36
|
-
const tags = Array.isArray(candidate.tags) ? candidate.tags : [];
|
|
37
|
-
const hints = candidate.scoreHints || {};
|
|
38
|
-
const hintValues: unknown[] = [
|
|
39
|
-
...(hints.modelHints || []),
|
|
40
|
-
...(hints.generationSurfaceHints || []),
|
|
41
|
-
...(hints.taskHints || []),
|
|
42
|
-
...(hints.sizeHints || []),
|
|
43
|
-
...(hints.qualityHints || []),
|
|
44
|
-
];
|
|
45
|
-
let score = 0;
|
|
46
|
-
|
|
47
|
-
if (terms.length === 0) score += 1;
|
|
48
|
-
for (const term of terms) {
|
|
49
|
-
if (name.includes(term)) score += 18;
|
|
50
|
-
if (includesAny(tags, [term])) score += 12;
|
|
51
|
-
if (includesAny(hintValues, [term])) score += 14;
|
|
52
|
-
if (text.includes(term)) score += 5;
|
|
53
|
-
if (String(candidate.sourceFileId || "").toLowerCase().includes(term)) score += 4;
|
|
54
|
-
}
|
|
55
|
-
if (tags.some((tag) => tag === "trust:curated")) score += 5;
|
|
56
|
-
if (candidate.warnings?.length) score -= candidate.warnings.length * 3;
|
|
57
|
-
|
|
58
|
-
return { ...candidate, score };
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
return ranked
|
|
62
|
-
.filter((candidate) => terms.length === 0 || (candidate.score ?? 0) > 0)
|
|
63
|
-
.sort((a, b) => (b.score ?? 0) - (a.score ?? 0) || String(a.name).localeCompare(String(b.name)))
|
|
64
|
-
.slice(0, boundedLimit);
|
|
65
|
-
}
|
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
import type { RouteRuntimeContext } from "../runtimeContext.js";
|
|
2
|
-
|
|
3
|
-
export type PromptImportCtx = RouteRuntimeContext;
|
|
4
|
-
|
|
5
|
-
export interface PromptImportLimits {
|
|
6
|
-
maxFileBytesForPreview: number;
|
|
7
|
-
maxPromptCandidatesPerFile: number;
|
|
8
|
-
maxPromptCandidatesPerImport: number;
|
|
9
|
-
fetchTimeoutMs: number;
|
|
10
|
-
maxCandidateChars: number;
|
|
11
|
-
minCandidateChars: number;
|
|
12
|
-
maxSourceCharsScanned: number;
|
|
13
|
-
maxRepoIndexFiles?: number;
|
|
14
|
-
searchLimit?: number;
|
|
15
|
-
ttlMs?: number;
|
|
16
|
-
maxFolderFiles?: number;
|
|
17
|
-
maxFolderPreviewFiles?: number;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export interface PromptCandidateSource {
|
|
21
|
-
kind: string;
|
|
22
|
-
owner?: string;
|
|
23
|
-
repo?: string;
|
|
24
|
-
ref?: string;
|
|
25
|
-
path?: string;
|
|
26
|
-
htmlUrl?: string;
|
|
27
|
-
sourceId?: string;
|
|
28
|
-
filename?: string;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export interface PromptCandidateScoreHints {
|
|
32
|
-
modelHints?: string[];
|
|
33
|
-
generationSurfaceHints?: string[];
|
|
34
|
-
taskHints?: string[];
|
|
35
|
-
sizeHints?: string[];
|
|
36
|
-
qualityHints?: string[];
|
|
37
|
-
warnings?: string[];
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export interface PromptCandidate {
|
|
41
|
-
id: string;
|
|
42
|
-
candidateId?: string;
|
|
43
|
-
name: string;
|
|
44
|
-
text: string;
|
|
45
|
-
textPreview: string;
|
|
46
|
-
tags: string[];
|
|
47
|
-
warnings: string[];
|
|
48
|
-
source: PromptCandidateSource;
|
|
49
|
-
sourceFileId?: string;
|
|
50
|
-
headingPath: string | null;
|
|
51
|
-
ordinal: number;
|
|
52
|
-
promptHash: string;
|
|
53
|
-
scoreHints: PromptCandidateScoreHints;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
export interface CuratedSourceLike {
|
|
57
|
-
id: string;
|
|
58
|
-
repo: string;
|
|
59
|
-
owner?: string;
|
|
60
|
-
name?: string;
|
|
61
|
-
displayName?: string;
|
|
62
|
-
defaultRef: string;
|
|
63
|
-
allowedPaths: string[];
|
|
64
|
-
extensions: string[];
|
|
65
|
-
sourceType?: string;
|
|
66
|
-
licenseSpdx: string;
|
|
67
|
-
requiresAttribution?: boolean;
|
|
68
|
-
trustTier: string;
|
|
69
|
-
lastVerifiedAt?: string | null;
|
|
70
|
-
notes?: string;
|
|
71
|
-
searchSeeds?: string[];
|
|
72
|
-
defaultSearch?: boolean;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
export interface GitHubFileSource {
|
|
76
|
-
kind?: string;
|
|
77
|
-
owner?: string;
|
|
78
|
-
repo?: string;
|
|
79
|
-
ref?: string;
|
|
80
|
-
path?: string;
|
|
81
|
-
extension?: string;
|
|
82
|
-
htmlUrl?: string;
|
|
83
|
-
rawUrl: string;
|
|
84
|
-
tags?: string[];
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
export interface DiscoveryRepo {
|
|
88
|
-
full_name?: string;
|
|
89
|
-
description?: string | null;
|
|
90
|
-
topics?: string[];
|
|
91
|
-
pushed_at?: string | null;
|
|
92
|
-
stargazers_count?: number;
|
|
93
|
-
forks_count?: number;
|
|
94
|
-
open_issues_count?: number;
|
|
95
|
-
updated_at?: string | null;
|
|
96
|
-
license?: { spdx_id?: string | null } | null;
|
|
97
|
-
archived?: boolean;
|
|
98
|
-
disabled?: boolean;
|
|
99
|
-
fork?: boolean;
|
|
100
|
-
default_branch?: string | null;
|
|
101
|
-
html_url?: string | null;
|
|
102
|
-
language?: string | null;
|
|
103
|
-
}
|
package/lib/providerOptions.ts
DELETED
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import type { RuntimeContext } from "./runtimeContext.js";
|
|
2
|
-
import { normalizeImageModel, normalizeReasoningEffort, normalizeGrokImageModel } from "./imageModels.js";
|
|
3
|
-
|
|
4
|
-
export function resolveProviderOptions(ctx: RuntimeContext | null | undefined, {
|
|
5
|
-
provider = "oauth",
|
|
6
|
-
rawModel,
|
|
7
|
-
rawReasoningEffort,
|
|
8
|
-
rawSize = "1024x1024",
|
|
9
|
-
rawWebSearchEnabled = true,
|
|
10
|
-
searchMode = "on",
|
|
11
|
-
}: any = {}) {
|
|
12
|
-
if (provider === "grok") {
|
|
13
|
-
const grokCfg: { defaultImageModel?: string } = (ctx?.config as any)?.grokProvider || {};
|
|
14
|
-
const modelInput = rawModel || grokCfg.defaultImageModel;
|
|
15
|
-
const grokModelCheck = normalizeGrokImageModel(modelInput);
|
|
16
|
-
if (grokModelCheck.error) return { error: grokModelCheck.error, code: grokModelCheck.code, status: grokModelCheck.status };
|
|
17
|
-
return {
|
|
18
|
-
provider: "grok" as const,
|
|
19
|
-
model: grokModelCheck.model,
|
|
20
|
-
reasoningEffort: "none",
|
|
21
|
-
size: rawSize,
|
|
22
|
-
webSearchEnabled: true,
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const activeProvider = provider === "api" ? "api" : "oauth";
|
|
27
|
-
const apiConfig: { defaultImageModel?: string; defaultReasoningEffort?: string; defaultSize?: string; allowWebSearch?: boolean } = (ctx?.config as { apiProvider?: any })?.apiProvider || {};
|
|
28
|
-
const modelInput = activeProvider === "api"
|
|
29
|
-
? (rawModel || apiConfig.defaultImageModel || "gpt-5.4-mini")
|
|
30
|
-
: rawModel;
|
|
31
|
-
const modelCheck = normalizeImageModel(ctx, modelInput);
|
|
32
|
-
if (modelCheck.error) return { error: modelCheck.error, code: modelCheck.code, status: modelCheck.status };
|
|
33
|
-
|
|
34
|
-
const reasoningInput = activeProvider === "api"
|
|
35
|
-
? (rawReasoningEffort || apiConfig.defaultReasoningEffort || "low")
|
|
36
|
-
: rawReasoningEffort;
|
|
37
|
-
const reasoningCheck = normalizeReasoningEffort(ctx, reasoningInput);
|
|
38
|
-
if (reasoningCheck.error) {
|
|
39
|
-
return { error: reasoningCheck.error, code: reasoningCheck.code, status: reasoningCheck.status };
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
const size = activeProvider === "api" && (typeof rawSize !== "string" || rawSize.length === 0)
|
|
43
|
-
? (apiConfig.defaultSize || "1024x1024")
|
|
44
|
-
: rawSize;
|
|
45
|
-
const webSearchEnabled = activeProvider === "api"
|
|
46
|
-
? apiConfig.allowWebSearch !== false && rawWebSearchEnabled !== false && searchMode !== "off"
|
|
47
|
-
: rawWebSearchEnabled !== false && searchMode !== "off";
|
|
48
|
-
|
|
49
|
-
return {
|
|
50
|
-
provider: activeProvider,
|
|
51
|
-
model: modelCheck.model,
|
|
52
|
-
reasoningEffort: reasoningCheck.effort,
|
|
53
|
-
size,
|
|
54
|
-
webSearchEnabled,
|
|
55
|
-
};
|
|
56
|
-
}
|
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
import sharp from "sharp";
|
|
2
|
-
|
|
3
|
-
const DEFAULT_MAX_B64_BYTES = 6 * 1024 * 1024;
|
|
4
|
-
const DEFAULT_MAX_EDGE = 3840;
|
|
5
|
-
const DEFAULT_QUALITY_LADDER = [85, 75, 65, 55];
|
|
6
|
-
const FALLBACK_MAX_EDGE = 2048;
|
|
7
|
-
const FALLBACK_QUALITY_LADDER = [75, 65, 55];
|
|
8
|
-
|
|
9
|
-
function stripDataUrlPrefix(value: unknown) {
|
|
10
|
-
return String(value || "").replace(/^data:[^;]+;base64,/, "");
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
function toBase64(buffer: Buffer) {
|
|
14
|
-
return buffer.toString("base64");
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
async function encodeJpegWithinBudget(input: Buffer, {
|
|
18
|
-
maxB64Bytes,
|
|
19
|
-
maxEdge,
|
|
20
|
-
qualityLadder,
|
|
21
|
-
}: { maxB64Bytes: number; maxEdge: number; qualityLadder: number[] }) {
|
|
22
|
-
for (const quality of qualityLadder) {
|
|
23
|
-
const out = await sharp(input, { failOn: "none" })
|
|
24
|
-
.rotate()
|
|
25
|
-
.resize({
|
|
26
|
-
width: maxEdge,
|
|
27
|
-
height: maxEdge,
|
|
28
|
-
fit: "inside",
|
|
29
|
-
withoutEnlargement: true,
|
|
30
|
-
})
|
|
31
|
-
.flatten({ background: "#ffffff" })
|
|
32
|
-
.jpeg({ quality, progressive: true })
|
|
33
|
-
.toBuffer();
|
|
34
|
-
const b64 = toBase64(out);
|
|
35
|
-
if (b64.length <= maxB64Bytes) return { b64, compressed: true, quality, maxEdge };
|
|
36
|
-
}
|
|
37
|
-
return null;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
interface CompressOptions {
|
|
41
|
-
maxB64Bytes?: number;
|
|
42
|
-
maxEdge?: number;
|
|
43
|
-
qualityLadder?: number[];
|
|
44
|
-
fallbackMaxEdge?: number;
|
|
45
|
-
fallbackQualityLadder?: number[];
|
|
46
|
-
force?: boolean;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export async function compressReferenceB64ForOAuth(imageB64: string | undefined | null, options: CompressOptions = {}) {
|
|
50
|
-
const rawB64 = stripDataUrlPrefix(imageB64);
|
|
51
|
-
const maxB64Bytes = options.maxB64Bytes ?? DEFAULT_MAX_B64_BYTES;
|
|
52
|
-
const maxEdge = options.maxEdge ?? DEFAULT_MAX_EDGE;
|
|
53
|
-
const qualityLadder = options.qualityLadder ?? DEFAULT_QUALITY_LADDER;
|
|
54
|
-
if (!rawB64) return { b64: rawB64, compressed: false, inputBytes: 0, outputBytes: 0 };
|
|
55
|
-
|
|
56
|
-
const input = Buffer.from(rawB64, "base64");
|
|
57
|
-
const inputBytes = rawB64.length;
|
|
58
|
-
if (!options.force && inputBytes <= maxB64Bytes) {
|
|
59
|
-
return { b64: rawB64, compressed: false, inputBytes, outputBytes: inputBytes };
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
const primary = await encodeJpegWithinBudget(input, {
|
|
63
|
-
maxB64Bytes,
|
|
64
|
-
maxEdge,
|
|
65
|
-
qualityLadder,
|
|
66
|
-
});
|
|
67
|
-
if (primary) {
|
|
68
|
-
return { ...primary, inputBytes, outputBytes: primary.b64.length };
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
const fallback = await encodeJpegWithinBudget(input, {
|
|
72
|
-
maxB64Bytes,
|
|
73
|
-
maxEdge: options.fallbackMaxEdge ?? FALLBACK_MAX_EDGE,
|
|
74
|
-
qualityLadder: options.fallbackQualityLadder ?? FALLBACK_QUALITY_LADDER,
|
|
75
|
-
});
|
|
76
|
-
if (fallback) {
|
|
77
|
-
return { ...fallback, inputBytes, outputBytes: fallback.b64.length };
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
const err = new Error(`Reference image remains above ${maxB64Bytes} base64 bytes after compression`) as Error & { code?: string; status?: number };
|
|
81
|
-
err.code = "REF_TOO_LARGE";
|
|
82
|
-
err.status = 400;
|
|
83
|
-
throw err;
|
|
84
|
-
}
|