@cassiomc1/forgeloop 1.10.2 → 1.11.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/.cursor/rules/project-loop.mdc +2 -2
- package/.forgeloop/forgeloop.gitignore +1 -0
- package/.github/copilot-instructions.md +2 -2
- package/AGENTS.md +1 -0
- package/AGENT_COMPATIBILITY.md +7 -0
- package/CLAUDE.md +1 -0
- package/DOCS_INDEX.md +10 -0
- package/LOOP_SYSTEM_DESIGN.md +12 -0
- package/ORCHESTRATOR_INTEGRATION.md +9 -0
- package/PROTOCOL_INTEGRATION.md +17 -0
- package/README.md +12 -10
- package/THIRD_PARTY_NOTICES.md +11 -0
- package/THREAT_MODEL.md +21 -0
- package/benchmarks/repository-index/README.md +73 -0
- package/benchmarks/repository-index/queries.json +12 -0
- package/benchmarks/repository-index/run-hot-path.mjs +142 -0
- package/benchmarks/repository-index/run-persistent-transport.mjs +169 -0
- package/completions/_forgeloop +7 -1
- package/completions/forgeloop.bash +13 -1
- package/completions/forgeloop.fish +40 -1
- package/docs/AGENT_PROTOCOL_SUMMARY.md +8 -1
- package/docs/CLI_REFERENCE.md +114 -2
- package/docs/DOCUMENTATION_GUIDE.md +10 -5
- package/docs/GETTING_STARTED.md +17 -0
- package/docs/MCP.md +16 -1
- package/docs/PACKAGE_CONTENTS.md +7 -1
- package/docs/PERSISTENT_SEARCH_TRANSPORT.md +289 -0
- package/docs/RECIPES.md +30 -0
- package/docs/RELEASE_CHECKLIST.md +34 -0
- package/docs/REPOSITORY_INDEX.md +553 -0
- package/docs/TROUBLESHOOTING.md +147 -0
- package/docs/UNIVERSAL_INTEGRATION.md +30 -0
- package/docs/diagrams/README.md +10 -0
- package/package.json +11 -2
- package/scripts/update-tgrep-manifest.mjs +86 -0
- package/scripts/verify-tgrep-manifest.mjs +17 -0
- package/src/cli.js +35 -0
- package/src/commands/doctor.js +76 -1
- package/src/commands/index-rebuild.js +1 -0
- package/src/commands/index-setup.js +1 -0
- package/src/commands/index-start.js +1 -0
- package/src/commands/index-status.js +1 -0
- package/src/commands/index-stop.js +1 -0
- package/src/commands/init.js +39 -1
- package/src/commands/repository-index.js +111 -0
- package/src/commands/search.js +1 -0
- package/src/commands/update.js +32 -4
- package/src/core/cli-command-definitions.js +97 -3
- package/src/core/command-executors.js +35 -2
- package/src/core/command-input.js +23 -0
- package/src/core/error-codes.js +195 -0
- package/src/core/filesystem.js +10 -1
- package/src/core/integration-invocation-policy.js +27 -0
- package/src/core/integration-resources.js +16 -1
- package/src/core/protocol-info.js +23 -0
- package/src/integration.d.ts +90 -0
- package/src/integration.js +21 -0
- package/src/persistent-transport/client.js +293 -0
- package/src/persistent-transport/constants.js +24 -0
- package/src/persistent-transport/errors.js +38 -0
- package/src/persistent-transport/framing.js +61 -0
- package/src/persistent-transport/lifecycle.js +116 -0
- package/src/persistent-transport/ownership.js +184 -0
- package/src/persistent-transport/paths.js +31 -0
- package/src/persistent-transport/protocol.js +95 -0
- package/src/persistent-transport/server.js +256 -0
- package/src/persistent-transport/state.js +49 -0
- package/src/repository-index/args.js +59 -0
- package/src/repository-index/binary-manager.js +413 -0
- package/src/repository-index/constants.js +45 -0
- package/src/repository-index/errors.js +38 -0
- package/src/repository-index/lifecycle.js +17 -0
- package/src/repository-index/lock.js +113 -0
- package/src/repository-index/manifest.js +132 -0
- package/src/repository-index/metrics.js +30 -0
- package/src/repository-index/normalize-json.js +187 -0
- package/src/repository-index/paths.js +39 -0
- package/src/repository-index/platform.js +20 -0
- package/src/repository-index/process.js +140 -0
- package/src/repository-index/readiness.js +62 -0
- package/src/repository-index/search.js +262 -0
- package/src/repository-index/server.js +432 -0
- package/src/repository-index/status.js +397 -0
- package/src/repository-index/tgrep-manifest.json +38 -0
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { rebuildRepositoryIndex, setupRepositoryIndex, startRepositoryIndexServer, stopRepositoryIndexServer } from "../repository-index/server.js";
|
|
2
|
+
import { searchRepository } from "../repository-index/search.js";
|
|
3
|
+
import { formatRepositoryIndexStatus, getRepositoryIndexStatus, sanitizeRepositoryIndexStatus } from "../repository-index/status.js";
|
|
4
|
+
import { searchViaPersistentTransport } from "../persistent-transport/client.js";
|
|
5
|
+
|
|
6
|
+
function sanitizeLifecycleResult(result) {
|
|
7
|
+
const { status, indexed, ...rest } = result ?? {};
|
|
8
|
+
const publicIndexed = indexed && typeof indexed === "object"
|
|
9
|
+
? Object.fromEntries(Object.entries(indexed).filter(([key]) => !["root_path", "rootPath", "indexPath", "repositoryRoot"].includes(key)))
|
|
10
|
+
: indexed;
|
|
11
|
+
return {
|
|
12
|
+
...rest,
|
|
13
|
+
...(status ? { status: sanitizeRepositoryIndexStatus(status) } : {}),
|
|
14
|
+
...(indexed ? { indexed: publicIndexed } : {}),
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function nativeOptions(options, packageRoot) {
|
|
19
|
+
return {
|
|
20
|
+
packageRoot,
|
|
21
|
+
assetPath: options.assetPath ?? undefined,
|
|
22
|
+
binaryPath: options.binaryPath ?? undefined,
|
|
23
|
+
homeDirectory: options.homeDirectory ?? undefined,
|
|
24
|
+
force: options.force === true,
|
|
25
|
+
config: options.indexConfig ?? undefined,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export async function runRepositoryIndexSetup({ target, packageRoot, options = {} } = {}) {
|
|
30
|
+
const native = nativeOptions(options, packageRoot);
|
|
31
|
+
const result = await setupRepositoryIndex(target, native);
|
|
32
|
+
return sanitizeLifecycleResult({ ...result, status: result.status ?? await getRepositoryIndexStatus(target, { ...native, packageRoot, includeLocalPaths: true }) });
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export async function runRepositoryIndexStart({ target, packageRoot, options = {} } = {}) {
|
|
36
|
+
const native = nativeOptions(options, packageRoot);
|
|
37
|
+
const result = await startRepositoryIndexServer(target, native);
|
|
38
|
+
return sanitizeLifecycleResult({ ...result, status: result.status ?? await getRepositoryIndexStatus(target, { ...native, packageRoot, includeLocalPaths: true }) });
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export async function runRepositoryIndexStop({ target, packageRoot, options = {} } = {}) {
|
|
42
|
+
const native = nativeOptions(options, packageRoot);
|
|
43
|
+
const result = await stopRepositoryIndexServer(target, native);
|
|
44
|
+
return sanitizeLifecycleResult({ ...result, status: await getRepositoryIndexStatus(target, { ...native, packageRoot, skipNativeStatus: true }) });
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export async function runRepositoryIndexStatus({ target, packageRoot, options = {} } = {}) {
|
|
48
|
+
return getRepositoryIndexStatus(target, { ...nativeOptions(options, packageRoot), packageRoot });
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export async function runRepositoryIndexRebuild({ target, packageRoot, options = {} } = {}) {
|
|
52
|
+
const native = nativeOptions(options, packageRoot);
|
|
53
|
+
const result = await rebuildRepositoryIndex(target, native);
|
|
54
|
+
const status = result.status ?? await getRepositoryIndexStatus(target, { ...native, packageRoot });
|
|
55
|
+
const smoke = await searchRepository(target, {
|
|
56
|
+
...native,
|
|
57
|
+
pattern: "__FORGELOOP_INDEX_REBUILD_SMOKE__",
|
|
58
|
+
fixedStrings: true,
|
|
59
|
+
maxCount: 1,
|
|
60
|
+
});
|
|
61
|
+
return sanitizeLifecycleResult({
|
|
62
|
+
...result,
|
|
63
|
+
status: sanitizeRepositoryIndexStatus(status),
|
|
64
|
+
smokeSearch: {
|
|
65
|
+
status: "OK",
|
|
66
|
+
matchCount: smoke.matches.length,
|
|
67
|
+
nativeExitCode: smoke.metrics.exitCode,
|
|
68
|
+
},
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export async function runSearch({ target, packageRoot, options = {}, transport = "integration" } = {}) {
|
|
73
|
+
if (transport === "cli") {
|
|
74
|
+
return searchViaPersistentTransport(target, options, {
|
|
75
|
+
homeDirectory: options.homeDirectory,
|
|
76
|
+
idleTimeoutMs: options.persistentTransportIdleTimeoutMs,
|
|
77
|
+
startupTimeoutMs: options.persistentTransportStartupTimeoutMs,
|
|
78
|
+
requestTimeoutMs: options.persistentTransportRequestTimeoutMs,
|
|
79
|
+
env: options.env,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
return searchRepository(target, {
|
|
83
|
+
...options,
|
|
84
|
+
packageRoot,
|
|
85
|
+
pattern: options.pattern,
|
|
86
|
+
globs: options.globs ?? [],
|
|
87
|
+
types: options.types ?? [],
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export function formatRepositoryIndexResult(result) {
|
|
92
|
+
const status = result.status ?? result;
|
|
93
|
+
const lines = [
|
|
94
|
+
`Repository Index: ${status.health ?? "READY"}`,
|
|
95
|
+
`Engine: ${status.engine ?? "tgrep"} ${status.engineVersion ?? "unknown"}`,
|
|
96
|
+
`Index: ${status.indexPath ?? "unknown"}`,
|
|
97
|
+
`Server: ${status.server?.running ? `running (pid ${status.server.pid ?? "unknown"})` : "not running"}`,
|
|
98
|
+
];
|
|
99
|
+
if (result.rebuilt) lines.push("Rebuilt: yes");
|
|
100
|
+
if (result.setup) lines.push(`Setup: ${result.rebuilt ? "rebuilt" : "reused"}`);
|
|
101
|
+
if (result.stopped !== undefined) lines.push(`Stopped: ${result.stopped ? "yes" : "no"}`);
|
|
102
|
+
return `${lines.join("\n")}\n`;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export function formatSearchResult(result) {
|
|
106
|
+
if (result.query.filesWithMatches) return `${(result.files ?? []).join("\n")}${result.files?.length ? "\n" : "no matches\n"}`;
|
|
107
|
+
const lines = (result.matches ?? []).map((match) => `${match.path}:${match.line}${match.column ? `:${match.column}` : ""}:${match.text}`);
|
|
108
|
+
return `${lines.join("\n")}${lines.length ? "\n" : "no matches\n"}`;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export { formatRepositoryIndexStatus };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { runSearch, formatSearchResult } from "./repository-index.js";
|
package/src/commands/update.js
CHANGED
|
@@ -10,6 +10,8 @@ import {
|
|
|
10
10
|
} from "../core/manifest.js";
|
|
11
11
|
import { readTemplateEntries } from "../core/templates.js";
|
|
12
12
|
import { isNativeAdapterPath, LAYOUT_VERSION, LEGACY_PROFILE_PATH } from "../core/target-layout.js";
|
|
13
|
+
import { isRepositoryCandidate } from "../repository-index/lifecycle.js";
|
|
14
|
+
import { setupRepositoryIndex } from "../repository-index/server.js";
|
|
13
15
|
|
|
14
16
|
const LEGACY_CLEANUP_DIRECTORIES = Object.freeze(["ENG", "schemas"]);
|
|
15
17
|
|
|
@@ -295,7 +297,32 @@ async function migrateLegacyLayout({ target, dryRun, packageVersion, currentMani
|
|
|
295
297
|
return { actions, conflicts, manifest: nextManifest };
|
|
296
298
|
}
|
|
297
299
|
|
|
298
|
-
|
|
300
|
+
async function attachRepositoryIndexResult(result, { target, dryRun, packageRoot, repositoryIndex, repositoryIndexOptions = {} }) {
|
|
301
|
+
if (!repositoryIndex) return result;
|
|
302
|
+
if (!(await isRepositoryCandidate(target))) {
|
|
303
|
+
return { ...result, repositoryIndex: { status: "DEFERRED", required: true, reason: "target is not a Git repository" } };
|
|
304
|
+
}
|
|
305
|
+
if (dryRun) {
|
|
306
|
+
return { ...result, repositoryIndex: { status: "WOULD_SETUP", required: true, reason: "dry-run does not provision or execute the native index engine" } };
|
|
307
|
+
}
|
|
308
|
+
if (result.conflicts?.length > 0) {
|
|
309
|
+
return { ...result, repositoryIndex: { status: "BLOCKED", required: true, reason: "update conflicts must be resolved before index maintenance" } };
|
|
310
|
+
}
|
|
311
|
+
const setup = await setupRepositoryIndex(target, { ...repositoryIndexOptions, packageRoot });
|
|
312
|
+
return {
|
|
313
|
+
...result,
|
|
314
|
+
repositoryIndex: {
|
|
315
|
+
status: "READY",
|
|
316
|
+
required: true,
|
|
317
|
+
health: setup.status?.health ?? "READY",
|
|
318
|
+
engine: setup.status?.engine ?? "tgrep",
|
|
319
|
+
engineVersion: setup.status?.engineVersion ?? null,
|
|
320
|
+
server: setup.status?.server ?? null,
|
|
321
|
+
},
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
export async function runUpdate({ target, dryRun, packageRoot, packageVersion, hooks = {}, repositoryIndex, repositoryIndexOptions }) {
|
|
299
326
|
const currentManifest = await readManifest(target);
|
|
300
327
|
if (!currentManifest) {
|
|
301
328
|
throw new Error("No .forgeloop/manifest.json found; run forgeloop init first.");
|
|
@@ -303,7 +330,8 @@ export async function runUpdate({ target, dryRun, packageRoot, packageVersion, h
|
|
|
303
330
|
|
|
304
331
|
const entries = await readTemplateEntries(packageRoot);
|
|
305
332
|
if ((currentManifest.layoutVersion ?? 1) < LAYOUT_VERSION) {
|
|
306
|
-
|
|
333
|
+
const result = await migrateLegacyLayout({ target, dryRun, packageVersion, currentManifest, entries, hooks });
|
|
334
|
+
return attachRepositoryIndexResult(result, { target, dryRun, packageRoot, repositoryIndex, repositoryIndexOptions });
|
|
307
335
|
}
|
|
308
336
|
|
|
309
337
|
const nextManifest = structuredClone(currentManifest);
|
|
@@ -405,7 +433,7 @@ export async function runUpdate({ target, dryRun, packageRoot, packageVersion, h
|
|
|
405
433
|
}
|
|
406
434
|
|
|
407
435
|
if (conflicts.length > 0) {
|
|
408
|
-
return { actions, conflicts, manifest: currentManifest };
|
|
436
|
+
return attachRepositoryIndexResult({ actions, conflicts, manifest: currentManifest }, { target, dryRun, packageRoot, repositoryIndex, repositoryIndexOptions });
|
|
409
437
|
}
|
|
410
438
|
|
|
411
439
|
for (const relativePath of Object.keys(nextManifest.files)) {
|
|
@@ -423,5 +451,5 @@ export async function runUpdate({ target, dryRun, packageRoot, packageVersion, h
|
|
|
423
451
|
nextManifest.packageVersion = packageVersion;
|
|
424
452
|
await writeManifest(target, nextManifest, { dryRun });
|
|
425
453
|
await cleanupLegacyFiles({ target, dryRun, cleanupFiles, cleanupDirectories, hooks, actions, conflicts });
|
|
426
|
-
return { actions, conflicts, manifest: nextManifest };
|
|
454
|
+
return attachRepositoryIndexResult({ actions, conflicts, manifest: nextManifest }, { target, dryRun, packageRoot, repositoryIndex, repositoryIndexOptions });
|
|
427
455
|
}
|
|
@@ -81,7 +81,7 @@ export const CLI_COMMAND_DEFINITIONS = Object.freeze({
|
|
|
81
81
|
}),
|
|
82
82
|
writes: [".forgeloop/*", "AGENTS.md", "CLAUDE.md", ".cursor/rules/project-loop.mdc", ".github/copilot-instructions.md"],
|
|
83
83
|
removes: [],
|
|
84
|
-
mayExecuteExternalProcess:
|
|
84
|
+
mayExecuteExternalProcess: true,
|
|
85
85
|
description: "Initializes a target project directory with ForgeLoop discovery adapters, schemas, and templates.",
|
|
86
86
|
}),
|
|
87
87
|
doctor: Object.freeze({
|
|
@@ -97,9 +97,103 @@ export const CLI_COMMAND_DEFINITIONS = Object.freeze({
|
|
|
97
97
|
}),
|
|
98
98
|
writes: [".forgeloop/.manifest.json"],
|
|
99
99
|
removes: [],
|
|
100
|
-
mayExecuteExternalProcess:
|
|
100
|
+
mayExecuteExternalProcess: true,
|
|
101
101
|
description: "Diagnoses project health, discovers adapters, and optionally repairs missing template files.",
|
|
102
102
|
}),
|
|
103
|
+
"index-setup": Object.freeze({
|
|
104
|
+
name: "index-setup",
|
|
105
|
+
category: "project-maintenance",
|
|
106
|
+
mutation: "MUTATING",
|
|
107
|
+
options: Object.freeze({
|
|
108
|
+
...CLI_COMMON_OPTIONS,
|
|
109
|
+
"--asset": Object.freeze({ targetKey: "assetPath", parseType: "string", takesValue: true, valueName: "path", missingValueMessage: "--asset requires a local archive path", description: "use a preloaded pinned tgrep archive instead of downloading" }),
|
|
110
|
+
"--force": Object.freeze({ targetKey: "force", parseType: "boolean", takesValue: false, description: "rebuild the repository index even when metadata is current" }),
|
|
111
|
+
"--json": Object.freeze({ targetKey: "json", parseType: "boolean", takesValue: false, description: "emit repository-index setup as JSON" }),
|
|
112
|
+
}),
|
|
113
|
+
writes: [".forgeloop/repository-index/*"],
|
|
114
|
+
removes: [],
|
|
115
|
+
mayExecuteExternalProcess: true,
|
|
116
|
+
description: "Provisions the pinned tgrep engine, builds the repository index, and starts its owned watcher.",
|
|
117
|
+
}),
|
|
118
|
+
"index-start": Object.freeze({
|
|
119
|
+
name: "index-start",
|
|
120
|
+
category: "project-maintenance",
|
|
121
|
+
mutation: "MUTATING",
|
|
122
|
+
options: Object.freeze({
|
|
123
|
+
...CLI_COMMON_OPTIONS,
|
|
124
|
+
"--json": Object.freeze({ targetKey: "json", parseType: "boolean", takesValue: false, description: "emit repository-index start as JSON" }),
|
|
125
|
+
}),
|
|
126
|
+
writes: [".forgeloop/repository-index/engine-state.json"],
|
|
127
|
+
removes: [],
|
|
128
|
+
mayExecuteExternalProcess: true,
|
|
129
|
+
description: "Starts the owned tgrep repository-index watcher after an index has been built.",
|
|
130
|
+
}),
|
|
131
|
+
"index-stop": Object.freeze({
|
|
132
|
+
name: "index-stop",
|
|
133
|
+
category: "project-maintenance",
|
|
134
|
+
mutation: "MUTATING",
|
|
135
|
+
options: Object.freeze({
|
|
136
|
+
...CLI_COMMON_OPTIONS,
|
|
137
|
+
"--json": Object.freeze({ targetKey: "json", parseType: "boolean", takesValue: false, description: "emit repository-index stop as JSON" }),
|
|
138
|
+
}),
|
|
139
|
+
writes: [],
|
|
140
|
+
removes: [".forgeloop/repository-index/serve.json", ".forgeloop/repository-index/engine-state.json"],
|
|
141
|
+
mayExecuteExternalProcess: true,
|
|
142
|
+
description: "Stops only a tgrep server whose process identity is provably owned by ForgeLoop.",
|
|
143
|
+
}),
|
|
144
|
+
"index-status": Object.freeze({
|
|
145
|
+
name: "index-status",
|
|
146
|
+
category: "diagnostics",
|
|
147
|
+
mutation: "READ_ONLY",
|
|
148
|
+
options: Object.freeze({
|
|
149
|
+
...CLI_COMMON_OPTIONS,
|
|
150
|
+
"--json": Object.freeze({ targetKey: "json", parseType: "boolean", takesValue: false, description: "emit repository-index health as JSON" }),
|
|
151
|
+
}),
|
|
152
|
+
writes: [],
|
|
153
|
+
removes: [],
|
|
154
|
+
mayExecuteExternalProcess: true,
|
|
155
|
+
description: "Reports provider-neutral repository-index health, metadata, and owned-server status.",
|
|
156
|
+
}),
|
|
157
|
+
"index-rebuild": Object.freeze({
|
|
158
|
+
name: "index-rebuild",
|
|
159
|
+
category: "project-maintenance",
|
|
160
|
+
mutation: "MUTATING",
|
|
161
|
+
options: Object.freeze({
|
|
162
|
+
...CLI_COMMON_OPTIONS,
|
|
163
|
+
"--asset": Object.freeze({ targetKey: "assetPath", parseType: "string", takesValue: true, valueName: "path", missingValueMessage: "--asset requires a local archive path", description: "use a preloaded pinned tgrep archive instead of downloading" }),
|
|
164
|
+
"--json": Object.freeze({ targetKey: "json", parseType: "boolean", takesValue: false, description: "emit repository-index rebuild as JSON" }),
|
|
165
|
+
}),
|
|
166
|
+
writes: [".forgeloop/repository-index/*"],
|
|
167
|
+
removes: [".forgeloop/repository-index/tgrep/*"],
|
|
168
|
+
mayExecuteExternalProcess: true,
|
|
169
|
+
description: "Atomically rebuilds the repository index and restarts its owned watcher.",
|
|
170
|
+
}),
|
|
171
|
+
search: Object.freeze({
|
|
172
|
+
name: "search",
|
|
173
|
+
category: "diagnostics",
|
|
174
|
+
mutation: "READ_ONLY",
|
|
175
|
+
options: Object.freeze({
|
|
176
|
+
...CLI_COMMON_OPTIONS,
|
|
177
|
+
"<pattern>": Object.freeze({ targetKey: "pattern", parseType: "string", takesValue: true, isPositional: true, valueName: "pattern", description: "regular expression or literal search pattern" }),
|
|
178
|
+
"--glob": Object.freeze({ targetKey: "globs", parseType: "string", takesValue: true, repeatable: true, valueName: "glob", missingValueMessage: "--glob requires a pattern", description: "include files matching a glob" }),
|
|
179
|
+
"--type": Object.freeze({ targetKey: "types", parseType: "string", takesValue: true, repeatable: true, valueName: "type", missingValueMessage: "--type requires a file type", description: "include files of a tgrep type" }),
|
|
180
|
+
"--fixed-strings": Object.freeze({ targetKey: "fixedStrings", parseType: "boolean", takesValue: false, description: "treat the pattern as a literal string" }),
|
|
181
|
+
"--ignore-case": Object.freeze({ targetKey: "ignoreCase", parseType: "boolean", takesValue: false, description: "search case-insensitively" }),
|
|
182
|
+
"--smart-case": Object.freeze({ targetKey: "smartCase", parseType: "boolean", takesValue: false, description: "use case-insensitive search only for lowercase patterns" }),
|
|
183
|
+
"--word-regexp": Object.freeze({ targetKey: "wordRegexp", parseType: "boolean", takesValue: false, aliases: ["--word"], description: "match whole words only" }),
|
|
184
|
+
"--context": Object.freeze({ targetKey: "context", parseType: "non-negative-integer", takesValue: true, valueName: "lines", missingValueMessage: "--context requires a non-negative integer", description: "lines of context before and after matches" }),
|
|
185
|
+
"--before-context": Object.freeze({ targetKey: "beforeContext", parseType: "non-negative-integer", takesValue: true, valueName: "lines", missingValueMessage: "--before-context requires a non-negative integer", description: "lines of context before matches" }),
|
|
186
|
+
"--after-context": Object.freeze({ targetKey: "afterContext", parseType: "non-negative-integer", takesValue: true, valueName: "lines", missingValueMessage: "--after-context requires a non-negative integer", description: "lines of context after matches" }),
|
|
187
|
+
"--max-count": Object.freeze({ targetKey: "maxCount", parseType: "non-negative-integer", takesValue: true, valueName: "number", missingValueMessage: "--max-count requires a positive integer", description: "maximum matches per file" }),
|
|
188
|
+
"--files-with-matches": Object.freeze({ targetKey: "filesWithMatches", parseType: "boolean", takesValue: false, description: "return matching file paths only" }),
|
|
189
|
+
"--stats": Object.freeze({ targetKey: "stats", parseType: "boolean", takesValue: false, description: "include observed native search statistics" }),
|
|
190
|
+
"--json": Object.freeze({ targetKey: "json", parseType: "boolean", takesValue: false, description: "emit normalized provider-neutral search JSON" }),
|
|
191
|
+
}),
|
|
192
|
+
writes: [],
|
|
193
|
+
removes: [],
|
|
194
|
+
mayExecuteExternalProcess: true,
|
|
195
|
+
description: "Searches the ForgeLoop repository index through the provider-neutral search contract.",
|
|
196
|
+
}),
|
|
103
197
|
update: Object.freeze({
|
|
104
198
|
name: "update",
|
|
105
199
|
category: "project-maintenance",
|
|
@@ -110,7 +204,7 @@ export const CLI_COMMAND_DEFINITIONS = Object.freeze({
|
|
|
110
204
|
}),
|
|
111
205
|
writes: [".forgeloop/*", "AGENTS.md", "CLAUDE.md", ".cursor/rules/project-loop.mdc", ".github/copilot-instructions.md"],
|
|
112
206
|
removes: [],
|
|
113
|
-
mayExecuteExternalProcess:
|
|
207
|
+
mayExecuteExternalProcess: true,
|
|
114
208
|
description: "Updates installed templates, discovery adapters, and canonical engineering guides to the latest version.",
|
|
115
209
|
}),
|
|
116
210
|
activate: Object.freeze({
|
|
@@ -82,6 +82,14 @@ import { runAttestationVerify } from "../commands/attestation-verify.js";
|
|
|
82
82
|
import { runAttestationStatus } from "../commands/attestation-status.js";
|
|
83
83
|
import { runAttestationVerifyRange } from "../commands/attestation-verify-range.js";
|
|
84
84
|
import { exitCodeForAttestationResult } from "./exit-codes.js";
|
|
85
|
+
import {
|
|
86
|
+
runRepositoryIndexRebuild,
|
|
87
|
+
runRepositoryIndexSetup,
|
|
88
|
+
runRepositoryIndexStart,
|
|
89
|
+
runRepositoryIndexStatus,
|
|
90
|
+
runRepositoryIndexStop,
|
|
91
|
+
runSearch,
|
|
92
|
+
} from "../commands/repository-index.js";
|
|
85
93
|
|
|
86
94
|
/**
|
|
87
95
|
* Canonical transport-neutral command executors.
|
|
@@ -100,7 +108,7 @@ export const COMMAND_EXECUTORS = {
|
|
|
100
108
|
exitCode: 0,
|
|
101
109
|
}),
|
|
102
110
|
init: async ({ target, packageRoot, packageVersion, options }) => ({
|
|
103
|
-
result: await runInit({ target, dryRun: options.dryRun, packageRoot, packageVersion }),
|
|
111
|
+
result: await runInit({ target, dryRun: options.dryRun, packageRoot, packageVersion, repositoryIndex: true }),
|
|
104
112
|
exitCode: 0,
|
|
105
113
|
}),
|
|
106
114
|
doctor: async ({ target, packageRoot, options }) => {
|
|
@@ -110,6 +118,7 @@ export const COMMAND_EXECUTORS = {
|
|
|
110
118
|
adoptPaths: options.adopt,
|
|
111
119
|
strict: options.strict,
|
|
112
120
|
fix: options.fix,
|
|
121
|
+
repositoryIndex: true,
|
|
113
122
|
});
|
|
114
123
|
return { result, exitCode: result.ok ? 0 : 1 };
|
|
115
124
|
},
|
|
@@ -663,9 +672,33 @@ export const COMMAND_EXECUTORS = {
|
|
|
663
672
|
exitCode: 0,
|
|
664
673
|
}),
|
|
665
674
|
update: async ({ target, packageRoot, packageVersion, options }) => {
|
|
666
|
-
const result = await runUpdate({ target, dryRun: options.dryRun, packageRoot, packageVersion });
|
|
675
|
+
const result = await runUpdate({ target, dryRun: options.dryRun, packageRoot, packageVersion, repositoryIndex: true });
|
|
667
676
|
return { result, exitCode: result.conflicts.length === 0 ? 0 : 1 };
|
|
668
677
|
},
|
|
678
|
+
"index-setup": async ({ target, packageRoot, options }) => ({
|
|
679
|
+
result: await runRepositoryIndexSetup({ target, packageRoot, options }),
|
|
680
|
+
exitCode: 0,
|
|
681
|
+
}),
|
|
682
|
+
"index-start": async ({ target, packageRoot, options }) => ({
|
|
683
|
+
result: await runRepositoryIndexStart({ target, packageRoot, options }),
|
|
684
|
+
exitCode: 0,
|
|
685
|
+
}),
|
|
686
|
+
"index-stop": async ({ target, packageRoot, options }) => ({
|
|
687
|
+
result: await runRepositoryIndexStop({ target, packageRoot, options }),
|
|
688
|
+
exitCode: 0,
|
|
689
|
+
}),
|
|
690
|
+
"index-status": async ({ target, packageRoot, options }) => ({
|
|
691
|
+
result: await runRepositoryIndexStatus({ target, packageRoot, options }),
|
|
692
|
+
exitCode: 0,
|
|
693
|
+
}),
|
|
694
|
+
"index-rebuild": async ({ target, packageRoot, options }) => ({
|
|
695
|
+
result: await runRepositoryIndexRebuild({ target, packageRoot, options }),
|
|
696
|
+
exitCode: 0,
|
|
697
|
+
}),
|
|
698
|
+
search: async ({ target, packageRoot, options, transport = "integration" }) => ({
|
|
699
|
+
result: await runSearch({ target, packageRoot, options, transport }),
|
|
700
|
+
exitCode: 0,
|
|
701
|
+
}),
|
|
669
702
|
};
|
|
670
703
|
|
|
671
704
|
export const EXECUTOR_EXCEPTIONS = Object.freeze([
|
|
@@ -8,6 +8,12 @@ function inputError(message) {
|
|
|
8
8
|
return error;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
+
function validateSearchCommandInput(command, options, help) {
|
|
12
|
+
if (command === "search" && !help && (typeof options.pattern !== "string" || options.pattern.length === 0)) {
|
|
13
|
+
throw inputError("search requires a pattern");
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
11
17
|
/**
|
|
12
18
|
* Transport-neutral option defaults shared by the CLI parser and the
|
|
13
19
|
* programmatic command runtime so every executor observes the same
|
|
@@ -22,6 +28,22 @@ export function defaultCommandInputValues() {
|
|
|
22
28
|
strict: false,
|
|
23
29
|
fix: false,
|
|
24
30
|
adopt: [],
|
|
31
|
+
pattern: null,
|
|
32
|
+
globs: [],
|
|
33
|
+
types: [],
|
|
34
|
+
fixedStrings: false,
|
|
35
|
+
ignoreCase: false,
|
|
36
|
+
smartCase: false,
|
|
37
|
+
wordRegexp: false,
|
|
38
|
+
context: null,
|
|
39
|
+
beforeContext: null,
|
|
40
|
+
afterContext: null,
|
|
41
|
+
maxCount: null,
|
|
42
|
+
filesWithMatches: false,
|
|
43
|
+
stats: false,
|
|
44
|
+
assetPath: null,
|
|
45
|
+
binaryPath: null,
|
|
46
|
+
force: false,
|
|
25
47
|
workType: null,
|
|
26
48
|
surfaces: [],
|
|
27
49
|
risks: [],
|
|
@@ -118,6 +140,7 @@ export function validateForgeLoopCommandInput({ command, input, help = false } =
|
|
|
118
140
|
if (command === "task-create" && !options.taskId) {
|
|
119
141
|
throw inputError("task-create requires --task");
|
|
120
142
|
}
|
|
143
|
+
validateSearchCommandInput(command, options, help);
|
|
121
144
|
if (options.executionProfile !== null && options.executionProfile !== undefined) {
|
|
122
145
|
if (command !== "route") throw inputError(`executionProfile is not valid for ${command}`);
|
|
123
146
|
if (!EXECUTION_PROFILE_REQUESTS.includes(options.executionProfile)) {
|
package/src/core/error-codes.js
CHANGED
|
@@ -11,6 +11,36 @@ import {
|
|
|
11
11
|
E_VERIFICATION_ISOLATION_UNAVAILABLE,
|
|
12
12
|
} from "./verification-execution.js";
|
|
13
13
|
|
|
14
|
+
export const E_REPOSITORY_INDEX_PLATFORM_UNSUPPORTED = "E_REPOSITORY_INDEX_PLATFORM_UNSUPPORTED";
|
|
15
|
+
export const E_REPOSITORY_INDEX_ENGINE_MISSING = "E_REPOSITORY_INDEX_ENGINE_MISSING";
|
|
16
|
+
export const E_REPOSITORY_INDEX_ENGINE_DOWNLOAD_FAILED = "E_REPOSITORY_INDEX_ENGINE_DOWNLOAD_FAILED";
|
|
17
|
+
export const E_REPOSITORY_INDEX_ENGINE_CHECKSUM_MISMATCH = "E_REPOSITORY_INDEX_ENGINE_CHECKSUM_MISMATCH";
|
|
18
|
+
export const E_REPOSITORY_INDEX_ENGINE_BINARY_CHECKSUM_MISMATCH = "E_REPOSITORY_INDEX_ENGINE_BINARY_CHECKSUM_MISMATCH";
|
|
19
|
+
export const E_REPOSITORY_INDEX_ENGINE_EXTRACTION_FAILED = "E_REPOSITORY_INDEX_ENGINE_EXTRACTION_FAILED";
|
|
20
|
+
export const E_REPOSITORY_INDEX_ENGINE_VERSION_MISMATCH = "E_REPOSITORY_INDEX_ENGINE_VERSION_MISMATCH";
|
|
21
|
+
export const E_REPOSITORY_INDEX_ENGINE_EXECUTION_FAILED = "E_REPOSITORY_INDEX_ENGINE_EXECUTION_FAILED";
|
|
22
|
+
export const E_REPOSITORY_INDEX_OUTPUT_LIMIT = "E_REPOSITORY_INDEX_OUTPUT_LIMIT";
|
|
23
|
+
export const E_REPOSITORY_INDEX_NOT_INITIALIZED = "E_REPOSITORY_INDEX_NOT_INITIALIZED";
|
|
24
|
+
export const E_REPOSITORY_INDEX_INDEXING = "E_REPOSITORY_INDEX_INDEXING";
|
|
25
|
+
export const E_REPOSITORY_INDEX_SERVER_START_FAILED = "E_REPOSITORY_INDEX_SERVER_START_FAILED";
|
|
26
|
+
export const E_REPOSITORY_INDEX_SERVER_STOP_FAILED = "E_REPOSITORY_INDEX_SERVER_STOP_FAILED";
|
|
27
|
+
export const E_REPOSITORY_INDEX_SERVER_UNHEALTHY = "E_REPOSITORY_INDEX_SERVER_UNHEALTHY";
|
|
28
|
+
export const E_REPOSITORY_INDEX_SEARCH_FAILED = "E_REPOSITORY_INDEX_SEARCH_FAILED";
|
|
29
|
+
export const E_REPOSITORY_INDEX_OUTPUT_INVALID = "E_REPOSITORY_INDEX_OUTPUT_INVALID";
|
|
30
|
+
export const E_REPOSITORY_INDEX_REBUILD_FAILED = "E_REPOSITORY_INDEX_REBUILD_FAILED";
|
|
31
|
+
export const E_REPOSITORY_INDEX_REQUEST_INVALID = "E_REPOSITORY_INDEX_REQUEST_INVALID";
|
|
32
|
+
export const E_REPOSITORY_INDEX_LOCK_UNSAFE = "E_REPOSITORY_INDEX_LOCK_UNSAFE";
|
|
33
|
+
export const E_PERSISTENT_TRANSPORT_FRAME_INVALID = "E_PERSISTENT_TRANSPORT_FRAME_INVALID";
|
|
34
|
+
export const E_PERSISTENT_TRANSPORT_FRAME_TOO_LARGE = "E_PERSISTENT_TRANSPORT_FRAME_TOO_LARGE";
|
|
35
|
+
export const E_PERSISTENT_TRANSPORT_HOST_STALE = "E_PERSISTENT_TRANSPORT_HOST_STALE";
|
|
36
|
+
export const E_PERSISTENT_TRANSPORT_INVALID_REQUEST = "E_PERSISTENT_TRANSPORT_INVALID_REQUEST";
|
|
37
|
+
export const E_PERSISTENT_TRANSPORT_INVALID_RESPONSE = "E_PERSISTENT_TRANSPORT_INVALID_RESPONSE";
|
|
38
|
+
export const E_PERSISTENT_TRANSPORT_OWNERSHIP_UNVERIFIED = "E_PERSISTENT_TRANSPORT_OWNERSHIP_UNVERIFIED";
|
|
39
|
+
export const E_PERSISTENT_TRANSPORT_PROTOCOL_MISMATCH = "E_PERSISTENT_TRANSPORT_PROTOCOL_MISMATCH";
|
|
40
|
+
export const E_PERSISTENT_TRANSPORT_START_FAILED = "E_PERSISTENT_TRANSPORT_START_FAILED";
|
|
41
|
+
export const E_PERSISTENT_TRANSPORT_TIMEOUT = "E_PERSISTENT_TRANSPORT_TIMEOUT";
|
|
42
|
+
export const E_PERSISTENT_TRANSPORT_UNAVAILABLE = "E_PERSISTENT_TRANSPORT_UNAVAILABLE";
|
|
43
|
+
|
|
14
44
|
export const E_TASK_REQUIRED = "E_TASK_REQUIRED";
|
|
15
45
|
export const E_TASK_NOT_FOUND = "E_TASK_NOT_FOUND";
|
|
16
46
|
export const E_TASK_ALREADY_EXISTS = "E_TASK_ALREADY_EXISTS";
|
|
@@ -373,6 +403,140 @@ const ADVISORY_CONTEXT_AND_HANDOFF_ERROR_METADATA = Object.freeze(Object.fromEnt
|
|
|
373
403
|
})],
|
|
374
404
|
]));
|
|
375
405
|
|
|
406
|
+
const REPOSITORY_INDEX_ERROR_METADATA = Object.freeze(Object.fromEntries([
|
|
407
|
+
[E_REPOSITORY_INDEX_PLATFORM_UNSUPPORTED, [
|
|
408
|
+
"The current operating-system and architecture pair has no pinned tgrep release asset.",
|
|
409
|
+
"Use a supported platform or add a separately reviewed manifest asset; do not substitute a PATH executable.",
|
|
410
|
+
]],
|
|
411
|
+
[E_REPOSITORY_INDEX_ENGINE_MISSING, [
|
|
412
|
+
"The managed tgrep executable is absent, unreadable, or has not been provisioned.",
|
|
413
|
+
"Run forgeloop index-setup or preload the exact manifest archive with --asset.",
|
|
414
|
+
]],
|
|
415
|
+
[E_REPOSITORY_INDEX_ENGINE_DOWNLOAD_FAILED, [
|
|
416
|
+
"The pinned tgrep release asset could not be downloaded or read.",
|
|
417
|
+
"Retry with network access or preload the exact manifest archive; never bypass provisioning verification.",
|
|
418
|
+
]],
|
|
419
|
+
[E_REPOSITORY_INDEX_ENGINE_CHECKSUM_MISMATCH, [
|
|
420
|
+
"The tgrep archive or executable bytes do not match the pinned manifest SHA-256 digest.",
|
|
421
|
+
"Obtain the exact manifest asset and retry; do not install a checksum mismatch.",
|
|
422
|
+
]],
|
|
423
|
+
[E_REPOSITORY_INDEX_ENGINE_BINARY_CHECKSUM_MISMATCH, [
|
|
424
|
+
"The extracted or managed tgrep executable bytes do not match the pinned binary SHA-256 digest.",
|
|
425
|
+
"Run forgeloop index-setup or index-rebuild to repair the managed binary; do not run a mismatched executable.",
|
|
426
|
+
]],
|
|
427
|
+
[E_REPOSITORY_INDEX_ENGINE_EXTRACTION_FAILED, [
|
|
428
|
+
"The tgrep archive is malformed, unsafe, or could not be extracted to a temporary directory.",
|
|
429
|
+
"Use the exact supported archive and retry; unsafe paths and links are rejected.",
|
|
430
|
+
]],
|
|
431
|
+
[E_REPOSITORY_INDEX_ENGINE_VERSION_MISMATCH, [
|
|
432
|
+
"The executable reports a version different from the ForgeLoop-pinned tgrep version.",
|
|
433
|
+
"Provision the manifest-pinned tgrep release and retry; do not use an unpinned binary.",
|
|
434
|
+
]],
|
|
435
|
+
[E_REPOSITORY_INDEX_ENGINE_EXECUTION_FAILED, [
|
|
436
|
+
"A managed tgrep process could not be launched, completed, or stayed within its execution boundary.",
|
|
437
|
+
"Inspect the structured error and index status, then retry with the verified managed engine.",
|
|
438
|
+
]],
|
|
439
|
+
[E_REPOSITORY_INDEX_OUTPUT_LIMIT, [
|
|
440
|
+
"Managed tgrep output exceeded ForgeLoop's bounded process-output limit.",
|
|
441
|
+
"Narrow the search or resource policy and retry; oversized output is never promoted to a result.",
|
|
442
|
+
]],
|
|
443
|
+
[E_REPOSITORY_INDEX_NOT_INITIALIZED, [
|
|
444
|
+
"The repository index has no complete derived index available for the requested operation.",
|
|
445
|
+
"Run forgeloop index-setup or forgeloop index-rebuild for the selected repository.",
|
|
446
|
+
]],
|
|
447
|
+
[E_REPOSITORY_INDEX_INDEXING, [
|
|
448
|
+
"The repository index is still being built or reconciled and is not ready for the requested operation.",
|
|
449
|
+
"Wait for index-status to report READY, or use index-rebuild if the operation remains stuck.",
|
|
450
|
+
]],
|
|
451
|
+
[E_REPOSITORY_INDEX_SERVER_START_FAILED, [
|
|
452
|
+
"The ForgeLoop-owned tgrep watcher could not be started or did not become healthy.",
|
|
453
|
+
"Run index-status, inspect the structured reason, and retry index-start or index-rebuild.",
|
|
454
|
+
]],
|
|
455
|
+
[E_REPOSITORY_INDEX_SERVER_STOP_FAILED, [
|
|
456
|
+
"The ForgeLoop-owned tgrep watcher could not be stopped or its ownership could not be proven.",
|
|
457
|
+
"Use index-status and retry the canonical stop operation; never terminate processes by name or PID alone.",
|
|
458
|
+
]],
|
|
459
|
+
[E_REPOSITORY_INDEX_SERVER_UNHEALTHY, [
|
|
460
|
+
"Repository Index server, metadata, process identity, or index readiness validation failed.",
|
|
461
|
+
"Run index-status, then use index-rebuild after resolving the reported boundary.",
|
|
462
|
+
]],
|
|
463
|
+
[E_REPOSITORY_INDEX_SEARCH_FAILED, [
|
|
464
|
+
"The native tgrep search failed with an execution or provider error; no-match is not an error.",
|
|
465
|
+
"Inspect index-status and retry the query or rebuild the derived index; ForgeLoop does not fall back silently.",
|
|
466
|
+
]],
|
|
467
|
+
[E_REPOSITORY_INDEX_OUTPUT_INVALID, [
|
|
468
|
+
"Native tgrep output did not match the bounded provider-neutral JSON contract.",
|
|
469
|
+
"Treat the result as unusable, inspect the engine, and rebuild or provision the pinned release.",
|
|
470
|
+
]],
|
|
471
|
+
[E_REPOSITORY_INDEX_REBUILD_FAILED, [
|
|
472
|
+
"The derived repository index could not be rebuilt successfully.",
|
|
473
|
+
"Inspect the structured failure, resource policy, and repository paths, then retry index-rebuild.",
|
|
474
|
+
]],
|
|
475
|
+
[E_REPOSITORY_INDEX_REQUEST_INVALID, [
|
|
476
|
+
"Repository Index command input is outside the bounded provider-neutral request contract.",
|
|
477
|
+
"Correct the pattern, path filters, context, or lifecycle options and retry the canonical command.",
|
|
478
|
+
]],
|
|
479
|
+
[E_REPOSITORY_INDEX_LOCK_UNSAFE, [
|
|
480
|
+
"A Repository Index operation lock is malformed, conflicting, or cannot be safely acquired.",
|
|
481
|
+
"Wait for a concurrent operation to finish and retry; use status or rebuild for a persistent lock failure.",
|
|
482
|
+
]],
|
|
483
|
+
].map(([code, [meaning, safeResolution]]) => [code, Object.freeze({
|
|
484
|
+
code,
|
|
485
|
+
category: "repository-index",
|
|
486
|
+
classification: "PUBLIC_STABLE",
|
|
487
|
+
meaning,
|
|
488
|
+
safeResolution,
|
|
489
|
+
})])));
|
|
490
|
+
|
|
491
|
+
const PERSISTENT_TRANSPORT_ERROR_METADATA = Object.freeze(Object.fromEntries([
|
|
492
|
+
[E_PERSISTENT_TRANSPORT_FRAME_INVALID, [
|
|
493
|
+
"The local persistent-search byte stream did not contain a complete valid JSON frame.",
|
|
494
|
+
"Retry the bounded local request; inspect the host only if malformed frames recur.",
|
|
495
|
+
]],
|
|
496
|
+
[E_PERSISTENT_TRANSPORT_FRAME_TOO_LARGE, [
|
|
497
|
+
"A persistent-search request or response exceeded its bounded frame limit.",
|
|
498
|
+
"Narrow the search request or inspect the host resource boundary; oversized frames are rejected.",
|
|
499
|
+
]],
|
|
500
|
+
[E_PERSISTENT_TRANSPORT_HOST_STALE, [
|
|
501
|
+
"Persistent-search state points to a host process that is no longer running.",
|
|
502
|
+
"Retry the CLI search so ForgeLoop can remove only the verified stale host state and restart it.",
|
|
503
|
+
]],
|
|
504
|
+
[E_PERSISTENT_TRANSPORT_INVALID_REQUEST, [
|
|
505
|
+
"A local persistent-search request is outside the versioned transport contract.",
|
|
506
|
+
"Use the supported ForgeLoop search command or update the compatible client and host together.",
|
|
507
|
+
]],
|
|
508
|
+
[E_PERSISTENT_TRANSPORT_INVALID_RESPONSE, [
|
|
509
|
+
"The persistent-search host returned a response outside the versioned transport contract.",
|
|
510
|
+
"Retry once through the bounded recovery path; do not consume an unvalidated response.",
|
|
511
|
+
]],
|
|
512
|
+
[E_PERSISTENT_TRANSPORT_OWNERSHIP_UNVERIFIED, [
|
|
513
|
+
"ForgeLoop could not prove that the process or endpoint belongs to its user-scoped persistent-search host.",
|
|
514
|
+
"Do not terminate the process; inspect the endpoint and retry after resolving the ownership conflict.",
|
|
515
|
+
]],
|
|
516
|
+
[E_PERSISTENT_TRANSPORT_PROTOCOL_MISMATCH, [
|
|
517
|
+
"The persistent-search client and host do not agree on the supported protocol version.",
|
|
518
|
+
"ForgeLoop may replace only a verified compatible host; otherwise update the installed package and retry.",
|
|
519
|
+
]],
|
|
520
|
+
[E_PERSISTENT_TRANSPORT_START_FAILED, [
|
|
521
|
+
"The user-scoped persistent-search host could not start or become ready within its bounded startup window.",
|
|
522
|
+
"Inspect the structured diagnostics and retry; direct integration APIs remain available without this optimization.",
|
|
523
|
+
]],
|
|
524
|
+
[E_PERSISTENT_TRANSPORT_TIMEOUT, [
|
|
525
|
+
"A persistent-search connection, handshake, or request exceeded its bounded timeout.",
|
|
526
|
+
"Retry once through the ownership-checked recovery path and inspect host/index health if it persists.",
|
|
527
|
+
]],
|
|
528
|
+
[E_PERSISTENT_TRANSPORT_UNAVAILABLE, [
|
|
529
|
+
"The user-scoped persistent-search endpoint was not reachable.",
|
|
530
|
+
"ForgeLoop starts one verified local host and retries once; persistent failure is reported without an rg fallback.",
|
|
531
|
+
]],
|
|
532
|
+
].map(([code, [meaning, safeResolution]]) => [code, Object.freeze({
|
|
533
|
+
code,
|
|
534
|
+
category: "persistent-transport",
|
|
535
|
+
classification: "PUBLIC_STABLE",
|
|
536
|
+
meaning,
|
|
537
|
+
safeResolution,
|
|
538
|
+
})])));
|
|
539
|
+
|
|
376
540
|
/**
|
|
377
541
|
* Public, stable ForgeLoop error and reason codes documented for users and harnesses.
|
|
378
542
|
*/
|
|
@@ -380,6 +544,8 @@ export const PUBLIC_ERROR_CODES = Object.freeze({
|
|
|
380
544
|
...EXTENSION_PUBLIC_ERROR_CODES,
|
|
381
545
|
...STRUCTURAL_QUALITY_ERROR_METADATA,
|
|
382
546
|
...ADVISORY_CONTEXT_AND_HANDOFF_ERROR_METADATA,
|
|
547
|
+
...REPOSITORY_INDEX_ERROR_METADATA,
|
|
548
|
+
...PERSISTENT_TRANSPORT_ERROR_METADATA,
|
|
383
549
|
E_PREFLIGHT_NOT_READY: Object.freeze({
|
|
384
550
|
code: "E_PREFLIGHT_NOT_READY",
|
|
385
551
|
category: "preflight",
|
|
@@ -1259,6 +1425,35 @@ export const ALL_KNOWN_ERROR_CODES = Object.freeze(new Set([
|
|
|
1259
1425
|
E_BASELINE_RECORD_DURING_ACTIVE_TASK,
|
|
1260
1426
|
E_POLICY_INITIALIZATION_FAILED,
|
|
1261
1427
|
E_INIT_KIT_CONFLICT,
|
|
1428
|
+
E_REPOSITORY_INDEX_PLATFORM_UNSUPPORTED,
|
|
1429
|
+
E_REPOSITORY_INDEX_ENGINE_MISSING,
|
|
1430
|
+
E_REPOSITORY_INDEX_ENGINE_DOWNLOAD_FAILED,
|
|
1431
|
+
E_REPOSITORY_INDEX_ENGINE_CHECKSUM_MISMATCH,
|
|
1432
|
+
E_REPOSITORY_INDEX_ENGINE_BINARY_CHECKSUM_MISMATCH,
|
|
1433
|
+
E_REPOSITORY_INDEX_ENGINE_EXTRACTION_FAILED,
|
|
1434
|
+
E_REPOSITORY_INDEX_ENGINE_VERSION_MISMATCH,
|
|
1435
|
+
E_REPOSITORY_INDEX_ENGINE_EXECUTION_FAILED,
|
|
1436
|
+
E_REPOSITORY_INDEX_OUTPUT_LIMIT,
|
|
1437
|
+
E_REPOSITORY_INDEX_NOT_INITIALIZED,
|
|
1438
|
+
E_REPOSITORY_INDEX_INDEXING,
|
|
1439
|
+
E_REPOSITORY_INDEX_SERVER_START_FAILED,
|
|
1440
|
+
E_REPOSITORY_INDEX_SERVER_STOP_FAILED,
|
|
1441
|
+
E_REPOSITORY_INDEX_SERVER_UNHEALTHY,
|
|
1442
|
+
E_REPOSITORY_INDEX_SEARCH_FAILED,
|
|
1443
|
+
E_REPOSITORY_INDEX_OUTPUT_INVALID,
|
|
1444
|
+
E_REPOSITORY_INDEX_REBUILD_FAILED,
|
|
1445
|
+
E_REPOSITORY_INDEX_REQUEST_INVALID,
|
|
1446
|
+
E_REPOSITORY_INDEX_LOCK_UNSAFE,
|
|
1447
|
+
E_PERSISTENT_TRANSPORT_FRAME_INVALID,
|
|
1448
|
+
E_PERSISTENT_TRANSPORT_FRAME_TOO_LARGE,
|
|
1449
|
+
E_PERSISTENT_TRANSPORT_HOST_STALE,
|
|
1450
|
+
E_PERSISTENT_TRANSPORT_INVALID_REQUEST,
|
|
1451
|
+
E_PERSISTENT_TRANSPORT_INVALID_RESPONSE,
|
|
1452
|
+
E_PERSISTENT_TRANSPORT_OWNERSHIP_UNVERIFIED,
|
|
1453
|
+
E_PERSISTENT_TRANSPORT_PROTOCOL_MISMATCH,
|
|
1454
|
+
E_PERSISTENT_TRANSPORT_START_FAILED,
|
|
1455
|
+
E_PERSISTENT_TRANSPORT_TIMEOUT,
|
|
1456
|
+
E_PERSISTENT_TRANSPORT_UNAVAILABLE,
|
|
1262
1457
|
E_ACTION_INVALID,
|
|
1263
1458
|
E_ACTION_NOT_FOUND,
|
|
1264
1459
|
E_ACTION_STATE_MISMATCH,
|