voratiq 0.1.0-beta.21 → 0.1.0-beta.22
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 +18 -22
- package/dist/agents/launch/chat.d.ts +3 -1
- package/dist/agents/launch/chat.js +2 -0
- package/dist/bin.js +28 -7
- package/dist/cli/auto.js +1 -0
- package/dist/cli/contract.d.ts +26 -17
- package/dist/cli/contract.js +3 -1
- package/dist/cli/doctor.d.ts +12 -0
- package/dist/cli/doctor.js +115 -0
- package/dist/cli/list.js +4 -1
- package/dist/cli/operator-envelope.d.ts +19 -6
- package/dist/cli/operator-envelope.js +61 -1
- package/dist/cli/run.js +2 -0
- package/dist/cli/verify.d.ts +1 -1
- package/dist/cli/verify.js +48 -9
- package/dist/commands/auto/command.d.ts +1 -0
- package/dist/commands/auto/command.js +22 -12
- package/dist/commands/auto/errors.js +1 -1
- package/dist/commands/doctor/agents.d.ts +5 -0
- package/dist/commands/{init → doctor}/agents.js +37 -19
- package/dist/commands/doctor/command.d.ts +22 -0
- package/dist/commands/doctor/command.js +99 -0
- package/dist/commands/doctor/environment.d.ts +2 -0
- package/dist/commands/{init → doctor}/environment.js +38 -6
- package/dist/commands/{init/types.d.ts → doctor/fix-types.d.ts} +30 -9
- package/dist/commands/doctor/fix.d.ts +2 -0
- package/dist/commands/{init/command.js → doctor/fix.js} +106 -10
- package/dist/commands/doctor/reconcile.d.ts +2 -0
- package/dist/commands/doctor/reconcile.js +101 -0
- package/dist/commands/interactive/lifecycle.d.ts +2 -0
- package/dist/commands/interactive/lifecycle.js +8 -0
- package/dist/commands/list/command.d.ts +1 -0
- package/dist/commands/list/command.js +211 -352
- package/dist/commands/list/normalization.d.ts +56 -0
- package/dist/commands/list/normalization.js +317 -0
- package/dist/commands/message/command.d.ts +2 -1
- package/dist/commands/message/command.js +35 -14
- package/dist/commands/message/errors.d.ts +12 -3
- package/dist/commands/message/errors.js +19 -3
- package/dist/commands/reduce/command.js +16 -17
- package/dist/commands/reduce/errors.d.ts +2 -2
- package/dist/commands/reduce/errors.js +3 -3
- package/dist/commands/reduce/targets.js +11 -2
- package/dist/commands/root-launcher/command.js +12 -6
- package/dist/commands/run/command.d.ts +1 -0
- package/dist/commands/run/command.js +4 -1
- package/dist/commands/run/record-init.d.ts +2 -0
- package/dist/commands/run/record-init.js +2 -1
- package/dist/commands/run/spec-provenance.d.ts +37 -0
- package/dist/commands/run/spec-provenance.js +384 -0
- package/dist/commands/run/validation.d.ts +4 -0
- package/dist/commands/run/validation.js +25 -62
- package/dist/commands/spec/command.js +19 -6
- package/dist/commands/spec/errors.d.ts +5 -0
- package/dist/commands/spec/errors.js +9 -0
- package/dist/commands/verify/agents.d.ts +4 -2
- package/dist/commands/verify/agents.js +4 -11
- package/dist/commands/verify/command.js +15 -5
- package/dist/commands/verify/errors.d.ts +12 -0
- package/dist/commands/verify/errors.js +22 -0
- package/dist/commands/verify/targets.js +108 -12
- package/dist/competition/shared/preflight.d.ts +1 -1
- package/dist/competition/shared/preflight.js +15 -2
- package/dist/contracts/list.d.ts +129 -149
- package/dist/contracts/list.js +47 -99
- package/dist/domain/interactive/persistence/adapter.d.ts +23 -0
- package/dist/domain/interactive/persistence/adapter.js +42 -0
- package/dist/domain/message/model/types.d.ts +32 -0
- package/dist/domain/message/model/types.js +25 -0
- package/dist/domain/reduce/competition/adapter.js +21 -7
- package/dist/domain/reduce/competition/finalize.d.ts +7 -0
- package/dist/domain/reduce/competition/finalize.js +19 -0
- package/dist/domain/reduce/model/types.d.ts +3 -3
- package/dist/domain/run/competition/agents/artifacts.js +4 -2
- package/dist/domain/run/competition/errors.d.ts +1 -1
- package/dist/domain/run/competition/errors.js +4 -7
- package/dist/domain/run/model/types.d.ts +384 -0
- package/dist/domain/run/model/types.js +87 -0
- package/dist/domain/spec/competition/adapter.d.ts +1 -0
- package/dist/domain/spec/competition/adapter.js +6 -1
- package/dist/domain/spec/model/types.d.ts +3 -0
- package/dist/domain/spec/model/types.js +5 -0
- package/dist/domain/verify/competition/finalize.d.ts +9 -0
- package/dist/domain/verify/competition/finalize.js +22 -3
- package/dist/domain/verify/model/types.d.ts +2 -2
- package/dist/interactive/providers/mcp.d.ts +1 -0
- package/dist/interactive/providers/mcp.js +45 -7
- package/dist/interactive/substrate.js +20 -3
- package/dist/mcp/server.js +26 -9
- package/dist/policy/verification.js +18 -1
- package/dist/preflight/agents.d.ts +24 -0
- package/dist/preflight/agents.js +71 -0
- package/dist/preflight/environment.d.ts +6 -0
- package/dist/preflight/environment.js +17 -0
- package/dist/preflight/formatting.d.ts +5 -0
- package/dist/preflight/formatting.js +20 -0
- package/dist/preflight/index.d.ts +2 -0
- package/dist/preflight/index.js +5 -9
- package/dist/preflight/operator.d.ts +32 -0
- package/dist/preflight/operator.js +40 -0
- package/dist/preflight/settings.d.ts +2 -0
- package/dist/preflight/settings.js +17 -0
- package/dist/render/transcripts/interactive.d.ts +16 -0
- package/dist/render/transcripts/interactive.js +42 -0
- package/dist/render/transcripts/list.d.ts +41 -0
- package/dist/render/transcripts/list.js +152 -3
- package/dist/render/transcripts/message.d.ts +2 -1
- package/dist/render/transcripts/message.js +19 -20
- package/dist/render/transcripts/reduce.d.ts +1 -0
- package/dist/render/transcripts/reduce.js +21 -21
- package/dist/render/transcripts/root-launcher.js +2 -12
- package/dist/render/transcripts/run.d.ts +3 -0
- package/dist/render/transcripts/run.js +30 -4
- package/dist/render/transcripts/spec.js +5 -8
- package/dist/render/transcripts/verify.d.ts +5 -3
- package/dist/render/transcripts/verify.js +44 -31
- package/dist/render/utils/duration.d.ts +5 -0
- package/dist/render/utils/duration.js +6 -0
- package/dist/render/utils/runs.d.ts +1 -0
- package/dist/render/utils/runs.js +1 -0
- package/dist/render/utils/transcript-shell.d.ts +2 -1
- package/dist/render/utils/transcript-shell.js +19 -6
- package/dist/utils/errors.d.ts +2 -1
- package/dist/utils/errors.js +3 -1
- package/dist/utils/git.d.ts +1 -1
- package/dist/utils/git.js +25 -2
- package/dist/utils/list-target.d.ts +4 -0
- package/dist/utils/list-target.js +35 -0
- package/dist/utils/terminal.d.ts +1 -0
- package/dist/utils/terminal.js +11 -0
- package/dist/workspace/chat/artifacts.d.ts +7 -0
- package/dist/workspace/chat/artifacts.js +94 -3
- package/dist/workspace/errors.js +2 -2
- package/dist/workspace/managed-state.d.ts +32 -0
- package/dist/workspace/managed-state.js +103 -0
- package/dist/workspace/setup.js +66 -2
- package/dist/workspace/shim.d.ts +1 -0
- package/dist/workspace/shim.js +3 -3
- package/dist/workspace/structure.d.ts +1 -0
- package/dist/workspace/structure.js +1 -0
- package/package.json +2 -2
- package/dist/cli/init.d.ts +0 -15
- package/dist/cli/init.js +0 -70
- package/dist/commands/init/agents.d.ts +0 -4
- package/dist/commands/init/command.d.ts +0 -2
- package/dist/commands/init/environment.d.ts +0 -2
- package/dist/render/transcripts/init.d.ts +0 -7
- package/dist/render/transcripts/init.js +0 -83
- /package/dist/commands/{init/types.js → doctor/fix-types.js} +0 -0
package/dist/utils/git.d.ts
CHANGED
|
@@ -31,7 +31,7 @@ export declare function removeWorktree(options: {
|
|
|
31
31
|
root: string;
|
|
32
32
|
worktreePath: string;
|
|
33
33
|
}): Promise<void>;
|
|
34
|
-
export declare function gitAddAll(cwd: string): Promise<void>;
|
|
34
|
+
export declare function gitAddAll(cwd: string, excludedPaths?: readonly string[]): Promise<void>;
|
|
35
35
|
export declare function gitHasStagedChanges(cwd: string): Promise<boolean>;
|
|
36
36
|
export interface GitCommitOptions {
|
|
37
37
|
cwd: string;
|
package/dist/utils/git.js
CHANGED
|
@@ -20,7 +20,7 @@ export async function assertGitRepository(root) {
|
|
|
20
20
|
const repoRoot = await getGitRepositoryRoot(root);
|
|
21
21
|
if (repoRoot !== null) {
|
|
22
22
|
// We're in a repo but not at the root
|
|
23
|
-
throw new GitRepositoryError("Run `voratiq
|
|
23
|
+
throw new GitRepositoryError("Run `voratiq` from the repository root.", "not_repository_root", repoRoot);
|
|
24
24
|
}
|
|
25
25
|
// No git repository exists at all
|
|
26
26
|
throw new GitRepositoryError("No git repository found. Run `git init` or switch to an existing repository.", "no_repository");
|
|
@@ -80,8 +80,15 @@ export async function removeWorktree(options) {
|
|
|
80
80
|
cwd: root,
|
|
81
81
|
});
|
|
82
82
|
}
|
|
83
|
-
export async function gitAddAll(cwd) {
|
|
83
|
+
export async function gitAddAll(cwd, excludedPaths) {
|
|
84
84
|
await runGitCommand(["add", "-A"], { cwd });
|
|
85
|
+
const existingExcludedPaths = await resolveExistingGitPaths(cwd, excludedPaths);
|
|
86
|
+
if (existingExcludedPaths.length === 0) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
await runGitCommand(["reset", "--quiet", "HEAD", "--", ...existingExcludedPaths], {
|
|
90
|
+
cwd,
|
|
91
|
+
});
|
|
85
92
|
}
|
|
86
93
|
export async function gitHasStagedChanges(cwd) {
|
|
87
94
|
const output = await runGitCommand(["diff", "--cached", "--name-only"], {
|
|
@@ -146,3 +153,19 @@ function isHeadMissing(error) {
|
|
|
146
153
|
const isHeadExitCode = code === 128 || code === "128";
|
|
147
154
|
return headMissingMessage || (isHeadExitCode && normalized.includes("head"));
|
|
148
155
|
}
|
|
156
|
+
async function resolveExistingGitPaths(cwd, paths) {
|
|
157
|
+
if (!paths || paths.length === 0) {
|
|
158
|
+
return [];
|
|
159
|
+
}
|
|
160
|
+
const existing = [];
|
|
161
|
+
for (const path of paths) {
|
|
162
|
+
try {
|
|
163
|
+
await access(join(cwd, path), F_OK);
|
|
164
|
+
existing.push(path);
|
|
165
|
+
}
|
|
166
|
+
catch {
|
|
167
|
+
// Ignore missing excluded paths so git add works across repos and tests.
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return existing;
|
|
171
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ListJsonTargetRef } from "../contracts/list.js";
|
|
2
|
+
export declare const TARGET_TABLE_PREVIEW_LENGTH = 32;
|
|
3
|
+
export declare function formatTargetDisplay(target: ListJsonTargetRef): string;
|
|
4
|
+
export declare function formatTargetTablePreview(target: ListJsonTargetRef, maxLength?: number): string;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
const TARGET_SEPARATOR = ":";
|
|
2
|
+
const TARGET_ELISION = "...";
|
|
3
|
+
export const TARGET_TABLE_PREVIEW_LENGTH = 32;
|
|
4
|
+
export function formatTargetDisplay(target) {
|
|
5
|
+
if (target.kind === "file") {
|
|
6
|
+
return `file:${target.path}`;
|
|
7
|
+
}
|
|
8
|
+
if (target.agentId) {
|
|
9
|
+
return `${target.kind}:${target.sessionId}:${target.agentId}`;
|
|
10
|
+
}
|
|
11
|
+
return `${target.kind}:${target.sessionId}`;
|
|
12
|
+
}
|
|
13
|
+
export function formatTargetTablePreview(target, maxLength = TARGET_TABLE_PREVIEW_LENGTH) {
|
|
14
|
+
const display = formatTargetDisplay(target);
|
|
15
|
+
return middleElideTargetDisplay(display, maxLength);
|
|
16
|
+
}
|
|
17
|
+
function middleElideTargetDisplay(display, maxLength) {
|
|
18
|
+
if (display.length <= maxLength) {
|
|
19
|
+
return display;
|
|
20
|
+
}
|
|
21
|
+
if (maxLength <= TARGET_ELISION.length) {
|
|
22
|
+
return display.slice(0, maxLength);
|
|
23
|
+
}
|
|
24
|
+
const separatorIndex = display.indexOf(TARGET_SEPARATOR);
|
|
25
|
+
const prefixLength = separatorIndex >= 0 ? separatorIndex + 1 : 0;
|
|
26
|
+
const prefix = display.slice(0, prefixLength);
|
|
27
|
+
const suffixSource = display.slice(prefixLength);
|
|
28
|
+
const availableSuffixLength = maxLength - prefix.length - TARGET_ELISION.length;
|
|
29
|
+
if (availableSuffixLength <= 0) {
|
|
30
|
+
const prefixBudget = Math.max(0, maxLength - TARGET_ELISION.length);
|
|
31
|
+
return `${display.slice(0, prefixBudget)}${TARGET_ELISION}`;
|
|
32
|
+
}
|
|
33
|
+
const suffix = suffixSource.slice(-availableSuffixLength);
|
|
34
|
+
return `${prefix}${TARGET_ELISION}${suffix}`;
|
|
35
|
+
}
|
package/dist/utils/terminal.d.ts
CHANGED
|
@@ -3,3 +3,4 @@ export interface InteractiveShellOptions {
|
|
|
3
3
|
output?: NodeJS.WriteStream | null;
|
|
4
4
|
}
|
|
5
5
|
export declare function isInteractiveShell(options?: InteractiveShellOptions): boolean;
|
|
6
|
+
export declare function normalizeInteractiveTerm(env: NodeJS.ProcessEnv, options?: InteractiveShellOptions): string | undefined;
|
package/dist/utils/terminal.js
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
|
+
const FALLBACK_INTERACTIVE_TERM = "xterm-256color";
|
|
1
2
|
export function isInteractiveShell(options = {}) {
|
|
2
3
|
const input = options.input ?? process.stdin;
|
|
3
4
|
const output = options.output ?? process.stdout;
|
|
4
5
|
return Boolean(input?.isTTY && output?.isTTY);
|
|
5
6
|
}
|
|
7
|
+
export function normalizeInteractiveTerm(env, options = {}) {
|
|
8
|
+
if (!isInteractiveShell(options)) {
|
|
9
|
+
return env.TERM;
|
|
10
|
+
}
|
|
11
|
+
const term = env.TERM?.trim();
|
|
12
|
+
if (!term || term.toLowerCase() === "dumb") {
|
|
13
|
+
return FALLBACK_INTERACTIVE_TERM;
|
|
14
|
+
}
|
|
15
|
+
return env.TERM;
|
|
16
|
+
}
|
|
@@ -12,6 +12,7 @@ export interface PreserveChatArtifactsOptions {
|
|
|
12
12
|
agentRoot: string;
|
|
13
13
|
searchEnv?: NodeJS.ProcessEnv;
|
|
14
14
|
baseline?: ProviderTranscriptBaseline;
|
|
15
|
+
selectionHint?: ProviderTranscriptSelectionHint;
|
|
15
16
|
}
|
|
16
17
|
export interface ProviderTranscriptSnapshotEntry {
|
|
17
18
|
path: string;
|
|
@@ -19,5 +20,11 @@ export interface ProviderTranscriptSnapshotEntry {
|
|
|
19
20
|
mtimeMs: number;
|
|
20
21
|
}
|
|
21
22
|
export type ProviderTranscriptBaseline = readonly ProviderTranscriptSnapshotEntry[];
|
|
23
|
+
export interface CodexSessionMetaSelectionHint {
|
|
24
|
+
strategy: "codex-session-meta";
|
|
25
|
+
cwd: string;
|
|
26
|
+
minStartedAt?: string;
|
|
27
|
+
}
|
|
28
|
+
export type ProviderTranscriptSelectionHint = CodexSessionMetaSelectionHint;
|
|
22
29
|
export declare function snapshotProviderTranscripts(options: Omit<PreserveChatArtifactsOptions, "baseline">): Promise<ProviderTranscriptBaseline>;
|
|
23
30
|
export declare function preserveProviderChatTranscripts(options: PreserveChatArtifactsOptions): Promise<ChatArtifactCaptureResult>;
|
|
@@ -42,7 +42,20 @@ export async function preserveProviderChatTranscripts(options) {
|
|
|
42
42
|
};
|
|
43
43
|
}
|
|
44
44
|
const existing = await locateExistingChatArtifact(agentRoot);
|
|
45
|
-
|
|
45
|
+
let selection;
|
|
46
|
+
try {
|
|
47
|
+
selection = await selectTranscriptFiles({
|
|
48
|
+
providerId,
|
|
49
|
+
transcriptPaths: candidatePaths,
|
|
50
|
+
selectionHint: options.selectionHint,
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
return {
|
|
55
|
+
status: "error",
|
|
56
|
+
error: error instanceof Error ? error : new Error(String(error)),
|
|
57
|
+
};
|
|
58
|
+
}
|
|
46
59
|
if (!selection) {
|
|
47
60
|
if (existing !== undefined) {
|
|
48
61
|
return {
|
|
@@ -101,10 +114,21 @@ async function locateExistingChatArtifact(agentRoot) {
|
|
|
101
114
|
}
|
|
102
115
|
return undefined;
|
|
103
116
|
}
|
|
104
|
-
function selectTranscriptFiles(
|
|
117
|
+
async function selectTranscriptFiles(options) {
|
|
118
|
+
const { providerId, transcriptPaths, selectionHint } = options;
|
|
105
119
|
const jsonlFiles = transcriptPaths.filter((path) => path.toLowerCase().endsWith(".jsonl"));
|
|
106
120
|
if (jsonlFiles.length > 0) {
|
|
107
|
-
|
|
121
|
+
const selectedJsonlFiles = await filterJsonlTranscriptFilesByHint({
|
|
122
|
+
providerId,
|
|
123
|
+
files: jsonlFiles,
|
|
124
|
+
selectionHint,
|
|
125
|
+
});
|
|
126
|
+
if (selectedJsonlFiles.length > 0) {
|
|
127
|
+
return { format: "jsonl", files: selectedJsonlFiles };
|
|
128
|
+
}
|
|
129
|
+
if (selectionHint) {
|
|
130
|
+
return undefined;
|
|
131
|
+
}
|
|
108
132
|
}
|
|
109
133
|
const jsonFiles = transcriptPaths
|
|
110
134
|
.filter((path) => path.toLowerCase().endsWith(".json"))
|
|
@@ -114,6 +138,73 @@ function selectTranscriptFiles(transcriptPaths) {
|
|
|
114
138
|
}
|
|
115
139
|
return undefined;
|
|
116
140
|
}
|
|
141
|
+
async function filterJsonlTranscriptFilesByHint(options) {
|
|
142
|
+
const sortedFiles = [...options.files].sort();
|
|
143
|
+
const hint = options.selectionHint;
|
|
144
|
+
if (!hint) {
|
|
145
|
+
return sortedFiles;
|
|
146
|
+
}
|
|
147
|
+
if (options.providerId !== "codex" ||
|
|
148
|
+
hint.strategy !== "codex-session-meta") {
|
|
149
|
+
return sortedFiles;
|
|
150
|
+
}
|
|
151
|
+
const matchingFiles = [];
|
|
152
|
+
for (const file of sortedFiles) {
|
|
153
|
+
const metadata = await readCodexSessionMetadata(file);
|
|
154
|
+
if (!metadata) {
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
if (metadata.cwd !== hint.cwd) {
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
if (hint.minStartedAt &&
|
|
161
|
+
metadata.startedAt &&
|
|
162
|
+
metadata.startedAt < hint.minStartedAt) {
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
matchingFiles.push(file);
|
|
166
|
+
}
|
|
167
|
+
if (matchingFiles.length === 1) {
|
|
168
|
+
return matchingFiles;
|
|
169
|
+
}
|
|
170
|
+
if (matchingFiles.length > 1) {
|
|
171
|
+
throw new Error(`Ambiguous Codex transcript provenance for cwd \`${hint.cwd}\`: ${matchingFiles.join(", ")}`);
|
|
172
|
+
}
|
|
173
|
+
return [];
|
|
174
|
+
}
|
|
175
|
+
async function readCodexSessionMetadata(path) {
|
|
176
|
+
let raw;
|
|
177
|
+
try {
|
|
178
|
+
raw = await readFile(path, "utf8");
|
|
179
|
+
}
|
|
180
|
+
catch {
|
|
181
|
+
return undefined;
|
|
182
|
+
}
|
|
183
|
+
const lines = raw.split(/\r?\n/u);
|
|
184
|
+
for (const line of lines) {
|
|
185
|
+
const trimmed = line.trim();
|
|
186
|
+
if (!trimmed) {
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
let parsed;
|
|
190
|
+
try {
|
|
191
|
+
parsed = JSON.parse(trimmed);
|
|
192
|
+
}
|
|
193
|
+
catch {
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
const record = parsed;
|
|
197
|
+
if (record.type !== "session_meta") {
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
const payload = record.payload?.payload ?? record.payload;
|
|
201
|
+
return {
|
|
202
|
+
cwd: typeof payload?.cwd === "string" ? payload.cwd : undefined,
|
|
203
|
+
startedAt: typeof payload?.timestamp === "string" ? payload.timestamp : undefined,
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
return undefined;
|
|
207
|
+
}
|
|
117
208
|
async function bundleJsonTranscripts(options) {
|
|
118
209
|
const { files, artifactPath, agentRoot, providerId } = options;
|
|
119
210
|
if (files.length === 0) {
|
package/dist/workspace/errors.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { HintedError } from "../utils/errors.js";
|
|
2
2
|
const DEFAULT_WORKSPACE_HINT = [
|
|
3
|
-
"Run `voratiq
|
|
3
|
+
"Run `voratiq doctor --fix` to repair workspace setup.",
|
|
4
4
|
];
|
|
5
5
|
export class WorkspaceError extends HintedError {
|
|
6
6
|
constructor(message, detailLines = [], hintLines = DEFAULT_WORKSPACE_HINT) {
|
|
@@ -29,7 +29,7 @@ export class WorkspaceWrongTypeEntryError extends WorkspaceError {
|
|
|
29
29
|
export class WorkspaceNotInitializedError extends WorkspaceError {
|
|
30
30
|
missingEntries;
|
|
31
31
|
constructor(missingEntries) {
|
|
32
|
-
super("Voratiq workspace is not initialized.", buildMissingEntryDetailLines(missingEntries), ["Run `voratiq
|
|
32
|
+
super("Voratiq workspace is not initialized.", buildMissingEntryDetailLines(missingEntries), ["Run `voratiq doctor --fix` to repair workspace setup."]);
|
|
33
33
|
this.missingEntries = missingEntries;
|
|
34
34
|
this.name = "WorkspaceNotInitializedError";
|
|
35
35
|
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { AgentPreset } from "../configs/agents/defaults.js";
|
|
2
|
+
export declare const MANAGED_STATE_VERSION = 1;
|
|
3
|
+
export interface ManagedConfigFingerprint {
|
|
4
|
+
fingerprint: string;
|
|
5
|
+
}
|
|
6
|
+
export interface ManagedAgentsFingerprint extends ManagedConfigFingerprint {
|
|
7
|
+
managedEntriesFingerprint: string;
|
|
8
|
+
}
|
|
9
|
+
export interface ManagedOrchestrationFingerprint extends ManagedConfigFingerprint {
|
|
10
|
+
preset: AgentPreset;
|
|
11
|
+
}
|
|
12
|
+
export interface ManagedStateSnapshot {
|
|
13
|
+
version: number;
|
|
14
|
+
configs: {
|
|
15
|
+
agents?: ManagedAgentsFingerprint;
|
|
16
|
+
orchestration?: ManagedOrchestrationFingerprint;
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
export interface UpdateManagedStateOptions {
|
|
20
|
+
agentsContent?: string;
|
|
21
|
+
orchestrationContent?: string;
|
|
22
|
+
orchestrationPreset?: AgentPreset;
|
|
23
|
+
}
|
|
24
|
+
export declare function readManagedState(root: string): Promise<ManagedStateSnapshot | undefined>;
|
|
25
|
+
export declare function updateManagedState(root: string, options: UpdateManagedStateOptions): Promise<{
|
|
26
|
+
path: string;
|
|
27
|
+
created: boolean;
|
|
28
|
+
updated: boolean;
|
|
29
|
+
}>;
|
|
30
|
+
export declare function computeManagedFingerprint(content: string): string;
|
|
31
|
+
export declare function isManagedFingerprintMatch(fingerprint: ManagedConfigFingerprint | undefined, content: string): boolean;
|
|
32
|
+
export declare function isManagedAgentsFingerprintMatch(fingerprint: ManagedAgentsFingerprint | undefined, content: string): boolean;
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
3
|
+
import { getAgentDefaultId, getSupportedAgentDefaults, } from "../configs/agents/defaults.js";
|
|
4
|
+
import { readAgentsConfig } from "../configs/agents/loader.js";
|
|
5
|
+
import { isFileSystemError } from "../utils/fs.js";
|
|
6
|
+
import { normalizeConfigText } from "../utils/yaml.js";
|
|
7
|
+
import { resolveWorkspacePath, VORATIQ_MANAGED_STATE_FILE, } from "./structure.js";
|
|
8
|
+
import { serializeAgentsConfigEntries } from "./templates.js";
|
|
9
|
+
export const MANAGED_STATE_VERSION = 1;
|
|
10
|
+
export async function readManagedState(root) {
|
|
11
|
+
const path = resolveWorkspacePath(root, VORATIQ_MANAGED_STATE_FILE);
|
|
12
|
+
try {
|
|
13
|
+
const content = await readFile(path, "utf8");
|
|
14
|
+
return JSON.parse(content);
|
|
15
|
+
}
|
|
16
|
+
catch (error) {
|
|
17
|
+
if (isFileSystemError(error) && error.code === "ENOENT") {
|
|
18
|
+
return undefined;
|
|
19
|
+
}
|
|
20
|
+
throw error;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export async function updateManagedState(root, options) {
|
|
24
|
+
const path = resolveWorkspacePath(root, VORATIQ_MANAGED_STATE_FILE);
|
|
25
|
+
const existing = await readManagedState(root);
|
|
26
|
+
const next = existing
|
|
27
|
+
? {
|
|
28
|
+
...existing,
|
|
29
|
+
version: MANAGED_STATE_VERSION,
|
|
30
|
+
configs: { ...existing.configs },
|
|
31
|
+
}
|
|
32
|
+
: { version: MANAGED_STATE_VERSION, configs: {} };
|
|
33
|
+
if (options.agentsContent !== undefined) {
|
|
34
|
+
next.configs.agents = {
|
|
35
|
+
fingerprint: computeManagedFingerprint(options.agentsContent),
|
|
36
|
+
managedEntriesFingerprint: computeManagedAgentsEntriesFingerprint(options.agentsContent),
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
if (options.orchestrationContent !== undefined) {
|
|
40
|
+
next.configs.orchestration = {
|
|
41
|
+
fingerprint: computeManagedFingerprint(options.orchestrationContent),
|
|
42
|
+
preset: options.orchestrationPreset ?? "pro",
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
const serialized = serializeManagedState(next);
|
|
46
|
+
const previousSerialized = existing ? serializeManagedState(existing) : "";
|
|
47
|
+
if (serialized === previousSerialized) {
|
|
48
|
+
return { path, created: false, updated: false };
|
|
49
|
+
}
|
|
50
|
+
await writeFile(path, serialized, "utf8");
|
|
51
|
+
return {
|
|
52
|
+
path,
|
|
53
|
+
created: existing === undefined,
|
|
54
|
+
updated: true,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
export function computeManagedFingerprint(content) {
|
|
58
|
+
return createHash("sha256")
|
|
59
|
+
.update(normalizeConfigText(content), "utf8")
|
|
60
|
+
.digest("hex");
|
|
61
|
+
}
|
|
62
|
+
export function isManagedFingerprintMatch(fingerprint, content) {
|
|
63
|
+
if (!fingerprint) {
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
return fingerprint.fingerprint === computeManagedFingerprint(content);
|
|
67
|
+
}
|
|
68
|
+
export function isManagedAgentsFingerprintMatch(fingerprint, content) {
|
|
69
|
+
if (!fingerprint) {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
return (fingerprint.fingerprint === computeManagedFingerprint(content) ||
|
|
73
|
+
fingerprint.managedEntriesFingerprint ===
|
|
74
|
+
computeManagedAgentsEntriesFingerprint(content));
|
|
75
|
+
}
|
|
76
|
+
function serializeManagedState(state) {
|
|
77
|
+
return `${JSON.stringify(state, null, 2)}\n`;
|
|
78
|
+
}
|
|
79
|
+
function computeManagedAgentsEntriesFingerprint(content) {
|
|
80
|
+
const config = readAgentsConfig(content);
|
|
81
|
+
const entriesById = new Map();
|
|
82
|
+
for (const entry of config.agents) {
|
|
83
|
+
entriesById.set(entry.id, normalizeAgentEntry(entry));
|
|
84
|
+
}
|
|
85
|
+
const managedEntries = getSupportedAgentDefaults()
|
|
86
|
+
.map((template) => entriesById.get(getAgentDefaultId(template)))
|
|
87
|
+
.filter((entry) => entry !== undefined);
|
|
88
|
+
return createHash("sha256")
|
|
89
|
+
.update(normalizeConfigText(`agents:\n${serializeAgentsConfigEntries(managedEntries)}`), "utf8")
|
|
90
|
+
.digest("hex");
|
|
91
|
+
}
|
|
92
|
+
function normalizeAgentEntry(entry) {
|
|
93
|
+
return {
|
|
94
|
+
id: entry.id,
|
|
95
|
+
provider: entry.provider,
|
|
96
|
+
model: entry.model,
|
|
97
|
+
enabled: entry.enabled !== false,
|
|
98
|
+
binary: entry.binary ?? "",
|
|
99
|
+
extraArgs: entry.extraArgs && entry.extraArgs.length > 0
|
|
100
|
+
? [...entry.extraArgs]
|
|
101
|
+
: undefined,
|
|
102
|
+
};
|
|
103
|
+
}
|
package/dist/workspace/setup.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
2
|
-
import { dirname, join } from "node:path";
|
|
2
|
+
import { dirname, join, resolve as resolveAbsolute } from "node:path";
|
|
3
3
|
import { readAgentsConfig } from "../configs/agents/loader.js";
|
|
4
4
|
import { loadEnvironmentConfig, } from "../configs/environment/loader.js";
|
|
5
5
|
import { buildDefaultOrchestrationTemplate } from "../configs/orchestration/bootstrap.js";
|
|
@@ -7,7 +7,8 @@ import { toErrorMessage } from "../utils/errors.js";
|
|
|
7
7
|
import { isDirectory, isFile, pathExists } from "../utils/fs.js";
|
|
8
8
|
import { relativeToRoot } from "../utils/path.js";
|
|
9
9
|
import { WorkspaceMissingEntryError, WorkspaceNotInitializedError, WorkspaceSetupError, WorkspaceWrongTypeEntryError, } from "./errors.js";
|
|
10
|
-
import {
|
|
10
|
+
import { updateManagedState } from "./managed-state.js";
|
|
11
|
+
import { resolveWorkspacePath, VORATIQ_AGENTS_FILE, VORATIQ_ENVIRONMENT_FILE, VORATIQ_INTERACTIVE_DIR, VORATIQ_INTERACTIVE_FILE, VORATIQ_INTERACTIVE_SESSIONS_DIR, VORATIQ_MANAGED_STATE_FILE, VORATIQ_MESSAGE_DIR, VORATIQ_MESSAGE_FILE, VORATIQ_MESSAGE_SESSIONS_DIR, VORATIQ_ORCHESTRATION_FILE, VORATIQ_REDUCTION_DIR, VORATIQ_REDUCTION_FILE, VORATIQ_REDUCTION_SESSIONS_DIR, VORATIQ_RUN_DIR, VORATIQ_RUN_FILE, VORATIQ_RUN_SESSIONS_DIR, VORATIQ_SANDBOX_FILE, VORATIQ_SPEC_DIR, VORATIQ_SPEC_FILE, VORATIQ_SPEC_SESSIONS_DIR, VORATIQ_VERIFICATION_CONFIG_FILE, VORATIQ_VERIFICATION_DIR, VORATIQ_VERIFICATION_FILE, VORATIQ_VERIFICATION_SESSIONS_DIR, VORATIQ_VERIFICATION_TEMPLATES_DIR, } from "./structure.js";
|
|
11
12
|
import { buildDefaultAgentsTemplate, buildDefaultEnvironmentTemplate, buildDefaultSandboxTemplate, } from "./templates.js";
|
|
12
13
|
import { buildDefaultVerificationConfigYaml, SHIPPED_VERIFICATION_TEMPLATES, } from "./verification-defaults.js";
|
|
13
14
|
async function seedVerificationSurface(root, options = {}) {
|
|
@@ -99,6 +100,12 @@ const WORKSPACE_CONFIG_SEGMENTS = [
|
|
|
99
100
|
VORATIQ_SANDBOX_FILE,
|
|
100
101
|
VORATIQ_ORCHESTRATION_FILE,
|
|
101
102
|
];
|
|
103
|
+
const VOLATILE_WORKSPACE_EXCLUDE_PATTERNS = [
|
|
104
|
+
"/.voratiq/*/index.json",
|
|
105
|
+
"/.voratiq/*/sessions/",
|
|
106
|
+
"/.voratiq/*/history.lock",
|
|
107
|
+
];
|
|
108
|
+
const VOLATILE_WORKSPACE_EXCLUDE_HEADER = "# voratiq runtime state (auto-managed)";
|
|
102
109
|
export async function createWorkspace(root) {
|
|
103
110
|
const createdDirectories = [];
|
|
104
111
|
const createdFiles = [];
|
|
@@ -109,6 +116,7 @@ export async function createWorkspace(root) {
|
|
|
109
116
|
const sandboxConfigPath = resolveWorkspacePath(root, VORATIQ_SANDBOX_FILE);
|
|
110
117
|
const orchestrationConfigPath = resolveWorkspacePath(root, VORATIQ_ORCHESTRATION_FILE);
|
|
111
118
|
const verificationConfigPath = resolveWorkspacePath(root, VORATIQ_VERIFICATION_CONFIG_FILE);
|
|
119
|
+
const managedStatePath = resolveWorkspacePath(root, VORATIQ_MANAGED_STATE_FILE);
|
|
112
120
|
const workspaceExists = await pathExists(workspaceDir);
|
|
113
121
|
const [agentsConfigExists, environmentConfigExists] = await Promise.all([
|
|
114
122
|
pathExists(agentsConfigPath),
|
|
@@ -123,6 +131,7 @@ export async function createWorkspace(root) {
|
|
|
123
131
|
await mkdir(workspaceDir, { recursive: true });
|
|
124
132
|
createdDirectories.push(relativeToRoot(root, workspaceDir));
|
|
125
133
|
}
|
|
134
|
+
await ensureWorkspaceGitExclude(root);
|
|
126
135
|
for (const domain of domainStructures) {
|
|
127
136
|
if (!(await pathExists(domain.directoryPath))) {
|
|
128
137
|
await mkdir(domain.directoryPath, { recursive: true });
|
|
@@ -165,6 +174,20 @@ export async function createWorkspace(root) {
|
|
|
165
174
|
});
|
|
166
175
|
createdFiles.push(relativeToRoot(root, orchestrationConfigPath));
|
|
167
176
|
}
|
|
177
|
+
if (!agentsConfigExists || !orchestrationConfigExists) {
|
|
178
|
+
const [agentsContent, orchestrationContent] = await Promise.all([
|
|
179
|
+
readFile(agentsConfigPath, "utf8"),
|
|
180
|
+
readFile(orchestrationConfigPath, "utf8"),
|
|
181
|
+
]);
|
|
182
|
+
const managedStateResult = await updateManagedState(root, {
|
|
183
|
+
agentsContent,
|
|
184
|
+
orchestrationContent,
|
|
185
|
+
orchestrationPreset: "pro",
|
|
186
|
+
});
|
|
187
|
+
if (managedStateResult.created) {
|
|
188
|
+
createdFiles.push(relativeToRoot(root, managedStatePath));
|
|
189
|
+
}
|
|
190
|
+
}
|
|
168
191
|
const seededVerification = await seedVerificationSurface(root, {
|
|
169
192
|
verificationConfigPath,
|
|
170
193
|
configExists: verificationExists,
|
|
@@ -178,6 +201,7 @@ export async function repairWorkspaceStructure(root, options = {}) {
|
|
|
178
201
|
const createdFiles = [];
|
|
179
202
|
const workspaceDir = resolveWorkspacePath(root);
|
|
180
203
|
await ensureWorkspaceDirectoryEntry(root, workspaceDir);
|
|
204
|
+
await ensureWorkspaceGitExclude(root);
|
|
181
205
|
// Additive repair must not mutate config semantics.
|
|
182
206
|
for (const configPath of resolveWorkspaceConfigPaths(root)) {
|
|
183
207
|
const kind = await detectPathKind(configPath);
|
|
@@ -359,6 +383,46 @@ async function detectPathKind(path) {
|
|
|
359
383
|
}
|
|
360
384
|
return "other";
|
|
361
385
|
}
|
|
386
|
+
async function ensureWorkspaceGitExclude(root) {
|
|
387
|
+
const excludePath = await resolveGitExcludePath(root);
|
|
388
|
+
if (!excludePath) {
|
|
389
|
+
return;
|
|
390
|
+
}
|
|
391
|
+
const existing = (await pathExists(excludePath))
|
|
392
|
+
? await readFile(excludePath, "utf8")
|
|
393
|
+
: "";
|
|
394
|
+
const lines = existing.split(/\r?\n/u);
|
|
395
|
+
const missingPatterns = VOLATILE_WORKSPACE_EXCLUDE_PATTERNS.filter((pattern) => !lines.includes(pattern));
|
|
396
|
+
if (missingPatterns.length === 0) {
|
|
397
|
+
return;
|
|
398
|
+
}
|
|
399
|
+
const nextLines = existing.length > 0 && !existing.endsWith("\n")
|
|
400
|
+
? [...lines, VOLATILE_WORKSPACE_EXCLUDE_HEADER, ...missingPatterns]
|
|
401
|
+
: [
|
|
402
|
+
...lines.filter((line, index, all) => !(index === all.length - 1 && line === "")),
|
|
403
|
+
VOLATILE_WORKSPACE_EXCLUDE_HEADER,
|
|
404
|
+
...missingPatterns,
|
|
405
|
+
];
|
|
406
|
+
await mkdir(dirname(excludePath), { recursive: true });
|
|
407
|
+
await writeFile(excludePath, `${nextLines.join("\n")}\n`, "utf8");
|
|
408
|
+
}
|
|
409
|
+
async function resolveGitExcludePath(root) {
|
|
410
|
+
const gitEntryPath = join(root, ".git");
|
|
411
|
+
const kind = await detectPathKind(gitEntryPath);
|
|
412
|
+
if (kind === "directory") {
|
|
413
|
+
return join(gitEntryPath, "info", "exclude");
|
|
414
|
+
}
|
|
415
|
+
if (kind !== "file") {
|
|
416
|
+
return undefined;
|
|
417
|
+
}
|
|
418
|
+
const raw = await readFile(gitEntryPath, "utf8");
|
|
419
|
+
const match = raw.match(/^gitdir:\s*(.+)\s*$/mu);
|
|
420
|
+
if (!match) {
|
|
421
|
+
return undefined;
|
|
422
|
+
}
|
|
423
|
+
const gitDir = resolveAbsolute(root, match[1]);
|
|
424
|
+
return join(gitDir, "info", "exclude");
|
|
425
|
+
}
|
|
362
426
|
async function validateWorkspaceIndexFile(root, domain) {
|
|
363
427
|
const displayPath = relativeToRoot(root, domain.indexPath);
|
|
364
428
|
let raw;
|
package/dist/workspace/shim.d.ts
CHANGED
package/dist/workspace/shim.js
CHANGED
|
@@ -4,7 +4,7 @@ import { fileURLToPath } from "node:url";
|
|
|
4
4
|
import { isFileSystemError } from "../utils/fs.js";
|
|
5
5
|
import { resolvePath } from "../utils/path.js";
|
|
6
6
|
import { WorkspaceSetupError } from "./errors.js";
|
|
7
|
-
const
|
|
7
|
+
export const WORKSPACE_SHIM_RELATIVE_PATH = [
|
|
8
8
|
"dist",
|
|
9
9
|
"commands",
|
|
10
10
|
"run",
|
|
@@ -16,8 +16,8 @@ function resolveCliInstallRoot() {
|
|
|
16
16
|
}
|
|
17
17
|
export async function ensureWorkspaceShim(options) {
|
|
18
18
|
const { workspacePath, cliInstallRoot = resolveCliInstallRoot() } = options;
|
|
19
|
-
const sourcePath = resolvePath(cliInstallRoot, ...
|
|
20
|
-
const targetPath = resolvePath(workspacePath, ...
|
|
19
|
+
const sourcePath = resolvePath(cliInstallRoot, ...WORKSPACE_SHIM_RELATIVE_PATH);
|
|
20
|
+
const targetPath = resolvePath(workspacePath, ...WORKSPACE_SHIM_RELATIVE_PATH);
|
|
21
21
|
try {
|
|
22
22
|
await access(sourcePath);
|
|
23
23
|
await mkdir(dirname(targetPath), { recursive: true });
|
|
@@ -27,6 +27,7 @@ export declare const VORATIQ_VERIFICATION_CONFIG_FILE = "verification.yaml";
|
|
|
27
27
|
export declare const VORATIQ_ENVIRONMENT_FILE = "environment.yaml";
|
|
28
28
|
export declare const VORATIQ_SANDBOX_FILE = "sandbox.yaml";
|
|
29
29
|
export declare const VORATIQ_ORCHESTRATION_FILE = "orchestration.yaml";
|
|
30
|
+
export declare const VORATIQ_MANAGED_STATE_FILE = "managed-state.json";
|
|
30
31
|
export declare const WORKSPACE_DIRNAME = "workspace";
|
|
31
32
|
export declare const CONTEXT_DIRNAME = "context";
|
|
32
33
|
export declare const STDOUT_FILENAME = "stdout.log";
|
|
@@ -28,6 +28,7 @@ export const VORATIQ_VERIFICATION_CONFIG_FILE = "verification.yaml";
|
|
|
28
28
|
export const VORATIQ_ENVIRONMENT_FILE = "environment.yaml";
|
|
29
29
|
export const VORATIQ_SANDBOX_FILE = "sandbox.yaml";
|
|
30
30
|
export const VORATIQ_ORCHESTRATION_FILE = "orchestration.yaml";
|
|
31
|
+
export const VORATIQ_MANAGED_STATE_FILE = "managed-state.json";
|
|
31
32
|
export const WORKSPACE_DIRNAME = "workspace";
|
|
32
33
|
export const CONTEXT_DIRNAME = "context";
|
|
33
34
|
export const STDOUT_FILENAME = "stdout.log";
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "voratiq",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.1.0-beta.22",
|
|
4
|
+
"description": "Run workflows, delegate to swarms, and verify outputs before you apply them.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agent-ensembles",
|
|
7
7
|
"agent-orchestration",
|
package/dist/cli/init.d.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { Command } from "commander";
|
|
2
|
-
import type { InitCommandResult } from "../commands/init/types.js";
|
|
3
|
-
import type { AgentPreset } from "../workspace/templates.js";
|
|
4
|
-
import { type CommandOutputWriter } from "./output.js";
|
|
5
|
-
export interface RunInitCommandResult extends InitCommandResult {
|
|
6
|
-
body: string;
|
|
7
|
-
}
|
|
8
|
-
export interface InitCommandOptions {
|
|
9
|
-
yes?: boolean;
|
|
10
|
-
preset?: AgentPreset;
|
|
11
|
-
presetProvided?: boolean;
|
|
12
|
-
writeOutput?: CommandOutputWriter;
|
|
13
|
-
}
|
|
14
|
-
export declare function runInitCommand(options?: InitCommandOptions): Promise<RunInitCommandResult>;
|
|
15
|
-
export declare function createInitCommand(): Command;
|