@nyxa/nyx-agent 0.4.1 → 0.5.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/README.md +52 -9
- package/dist/cli.js +11 -16
- package/dist/commands/init.js +87 -466
- package/dist/commands/run.js +16 -3
- package/dist/config/loadConfig.js +16 -3
- package/dist/config/schema.js +27 -146
- package/dist/runtime/gitLifecycle.js +19 -57
- package/dist/runtime/harness.js +26 -0
- package/dist/runtime/paths.js +0 -12
- package/dist/runtime/prompts.js +103 -0
- package/dist/runtime/runPhase.js +85 -254
- package/dist/runtime/runPipeline.js +395 -0
- package/dist/runtime/schemas.js +52 -0
- package/dist/runtime/scm.js +76 -0
- package/dist/runtime/validateResult.js +1 -3
- package/dist/runtime/workItems.js +42 -118
- package/package.json +2 -5
- package/dist/runtime/buildPrompt.js +0 -54
- package/dist/runtime/effectiveConfig.js +0 -14
- package/dist/runtime/renderTemplate.js +0 -28
- package/dist/runtime/runWorkflow.js +0 -680
- package/dist/runtime/validateWorkItem.js +0 -212
- package/dist/runtime/workItemAnnotations.js +0 -39
- package/docs/nyxagent-v0-spec.md +0 -742
- package/templates/default/prompts/closure.md +0 -30
- package/templates/default/prompts/execution.md +0 -11
- package/templates/default/prompts/finalize.md +0 -7
- package/templates/default/prompts/global-review.md +0 -24
- package/templates/default/prompts/global-revision.md +0 -9
- package/templates/default/prompts/pull-request.md +0 -23
- package/templates/default/prompts/repair-result.md +0 -29
- package/templates/default/prompts/review.md +0 -18
- package/templates/default/prompts/revision.md +0 -7
- package/templates/default/prompts/selection.md +0 -46
- package/templates/default/schemas/closure.schema.json +0 -35
- package/templates/default/schemas/global-review.schema.json +0 -60
- package/templates/default/schemas/pull-request.schema.json +0 -44
- package/templates/default/schemas/review.schema.json +0 -60
- package/templates/default/schemas/selection.schema.json +0 -135
|
@@ -1,212 +0,0 @@
|
|
|
1
|
-
import path from "node:path";
|
|
2
|
-
export function validateWorkItemIdentity(input) {
|
|
3
|
-
const workItems = input.config.work_items;
|
|
4
|
-
if (!workItems) {
|
|
5
|
-
return {
|
|
6
|
-
ok: false,
|
|
7
|
-
error: "Selected work item requires configured [work_items]"
|
|
8
|
-
};
|
|
9
|
-
}
|
|
10
|
-
if (!isRecord(input.workItem)) {
|
|
11
|
-
return { ok: false, error: "Selected work item must be an object" };
|
|
12
|
-
}
|
|
13
|
-
const source = input.workItem.source;
|
|
14
|
-
if (!isRecord(source)) {
|
|
15
|
-
return { ok: false, error: "Selected work item source must be an object" };
|
|
16
|
-
}
|
|
17
|
-
const key = input.workItem.key;
|
|
18
|
-
const sourceType = source.type;
|
|
19
|
-
const locator = source.locator;
|
|
20
|
-
if (typeof key !== "string" || key.length === 0) {
|
|
21
|
-
return { ok: false, error: "Selected work item key must be a non-empty string" };
|
|
22
|
-
}
|
|
23
|
-
if (input.seenWorkItemKeys?.includes(key) && key !== input.allowKnownKey) {
|
|
24
|
-
return {
|
|
25
|
-
ok: false,
|
|
26
|
-
error: `Selected work item key "${key}" was already seen in this run`
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
if (input.completedWorkItemKeys?.includes(key) &&
|
|
30
|
-
key !== input.allowKnownKey) {
|
|
31
|
-
return {
|
|
32
|
-
ok: false,
|
|
33
|
-
error: `Selected work item key "${key}" is already completed`
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
if (sourceType !== workItems.source) {
|
|
37
|
-
return {
|
|
38
|
-
ok: false,
|
|
39
|
-
error: `Selected work item source.type must be "${workItems.source}"`
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
if (typeof locator !== "string" || locator.length === 0) {
|
|
43
|
-
return {
|
|
44
|
-
ok: false,
|
|
45
|
-
error: "Selected work item source.locator must be a non-empty string"
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
if (key !== `${workItems.source}:${locator}`) {
|
|
49
|
-
return {
|
|
50
|
-
ok: false,
|
|
51
|
-
error: `Selected work item key must be "${workItems.source}:${locator}"`
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
if (workItems.source === "local") {
|
|
55
|
-
const localValidation = validateLocalLocator(locator, workItems.path);
|
|
56
|
-
if (!localValidation.ok) {
|
|
57
|
-
return localValidation;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
else {
|
|
61
|
-
const githubValidation = validateGitHubLocator(locator, workItems.repository);
|
|
62
|
-
if (!githubValidation.ok) {
|
|
63
|
-
return githubValidation;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
if (input.availableWorkItems) {
|
|
67
|
-
return validateCandidateMembership({
|
|
68
|
-
key,
|
|
69
|
-
sourceType,
|
|
70
|
-
locator,
|
|
71
|
-
availableWorkItems: input.availableWorkItems
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
|
-
return { ok: true };
|
|
75
|
-
}
|
|
76
|
-
export function validateWorkItemQueue(input) {
|
|
77
|
-
if (!Array.isArray(input.workItems)) {
|
|
78
|
-
return {
|
|
79
|
-
ok: false,
|
|
80
|
-
error: "Selected work_items must be an array"
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
if (input.workItems.length === 0) {
|
|
84
|
-
return {
|
|
85
|
-
ok: false,
|
|
86
|
-
error: "Selected work_items must contain at least one item"
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
const seen = new Set();
|
|
90
|
-
const normalized = [];
|
|
91
|
-
for (const [index, workItem] of input.workItems.entries()) {
|
|
92
|
-
const validation = validateWorkItemIdentity({
|
|
93
|
-
config: input.config,
|
|
94
|
-
workItem,
|
|
95
|
-
availableWorkItems: input.availableWorkItems,
|
|
96
|
-
seenWorkItemKeys: input.seenWorkItemKeys,
|
|
97
|
-
completedWorkItemKeys: input.completedWorkItemKeys
|
|
98
|
-
});
|
|
99
|
-
if (!validation.ok) {
|
|
100
|
-
return {
|
|
101
|
-
ok: false,
|
|
102
|
-
error: `Selected work_items[${index}] ${validation.error}`
|
|
103
|
-
};
|
|
104
|
-
}
|
|
105
|
-
const key = readObjectProperty(workItem, "key");
|
|
106
|
-
if (typeof key !== "string") {
|
|
107
|
-
return {
|
|
108
|
-
ok: false,
|
|
109
|
-
error: `Selected work_items[${index}] key must be a string`
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
if (seen.has(key)) {
|
|
113
|
-
return {
|
|
114
|
-
ok: false,
|
|
115
|
-
error: `Selected work_items contains duplicate key "${key}"`
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
seen.add(key);
|
|
119
|
-
const candidate = input.availableWorkItems?.find((item) => item.key === key);
|
|
120
|
-
normalized.push(candidate ?? workItem);
|
|
121
|
-
}
|
|
122
|
-
return { ok: true, workItems: normalized };
|
|
123
|
-
}
|
|
124
|
-
function validateCandidateMembership(input) {
|
|
125
|
-
const candidate = input.availableWorkItems.find((item) => item.key === input.key);
|
|
126
|
-
if (!candidate) {
|
|
127
|
-
return {
|
|
128
|
-
ok: false,
|
|
129
|
-
error: `Selected work item key "${input.key}" is not in available_work_items`
|
|
130
|
-
};
|
|
131
|
-
}
|
|
132
|
-
if (candidate.source.type !== input.sourceType ||
|
|
133
|
-
candidate.source.locator !== input.locator) {
|
|
134
|
-
return {
|
|
135
|
-
ok: false,
|
|
136
|
-
error: `Selected work item source does not match available_work_items entry "${input.key}"`
|
|
137
|
-
};
|
|
138
|
-
}
|
|
139
|
-
return { ok: true };
|
|
140
|
-
}
|
|
141
|
-
function validateLocalLocator(locator, configuredPath) {
|
|
142
|
-
const normalizedLocator = normalizeRelativePath(locator);
|
|
143
|
-
const normalizedPath = configuredPath
|
|
144
|
-
? normalizeRelativePath(configuredPath)
|
|
145
|
-
: undefined;
|
|
146
|
-
if (!normalizedLocator || normalizedLocator !== locator) {
|
|
147
|
-
return {
|
|
148
|
-
ok: false,
|
|
149
|
-
error: "Local work item locator must be a canonical relative path"
|
|
150
|
-
};
|
|
151
|
-
}
|
|
152
|
-
if (!normalizedPath) {
|
|
153
|
-
return {
|
|
154
|
-
ok: false,
|
|
155
|
-
error: "Local work item validation requires [work_items].path"
|
|
156
|
-
};
|
|
157
|
-
}
|
|
158
|
-
if (normalizedLocator !== normalizedPath &&
|
|
159
|
-
!normalizedLocator.startsWith(`${normalizedPath}/`)) {
|
|
160
|
-
return {
|
|
161
|
-
ok: false,
|
|
162
|
-
error: `Local work item locator must stay under "${normalizedPath}"`
|
|
163
|
-
};
|
|
164
|
-
}
|
|
165
|
-
return { ok: true };
|
|
166
|
-
}
|
|
167
|
-
function validateGitHubLocator(locator, repository) {
|
|
168
|
-
if (!repository) {
|
|
169
|
-
return {
|
|
170
|
-
ok: false,
|
|
171
|
-
error: "GitHub work item validation requires [work_items].repository"
|
|
172
|
-
};
|
|
173
|
-
}
|
|
174
|
-
const match = /^([A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+)#([1-9][0-9]*)$/.exec(locator);
|
|
175
|
-
if (!match) {
|
|
176
|
-
return {
|
|
177
|
-
ok: false,
|
|
178
|
-
error: 'GitHub work item locator must use "owner/repo#number"'
|
|
179
|
-
};
|
|
180
|
-
}
|
|
181
|
-
if (match[1] !== repository) {
|
|
182
|
-
return {
|
|
183
|
-
ok: false,
|
|
184
|
-
error: `GitHub work item locator must use repository "${repository}"`
|
|
185
|
-
};
|
|
186
|
-
}
|
|
187
|
-
return { ok: true };
|
|
188
|
-
}
|
|
189
|
-
function normalizeRelativePath(value) {
|
|
190
|
-
if (value.length === 0 ||
|
|
191
|
-
value.includes("\\") ||
|
|
192
|
-
path.posix.isAbsolute(value) ||
|
|
193
|
-
/^[A-Za-z]:[\\/]/.test(value)) {
|
|
194
|
-
return undefined;
|
|
195
|
-
}
|
|
196
|
-
const normalized = path.posix.normalize(value);
|
|
197
|
-
if (normalized === "." || normalized === ".." || normalized.startsWith("../")) {
|
|
198
|
-
return undefined;
|
|
199
|
-
}
|
|
200
|
-
return normalized;
|
|
201
|
-
}
|
|
202
|
-
function isRecord(value) {
|
|
203
|
-
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
204
|
-
}
|
|
205
|
-
function readObjectProperty(value, key) {
|
|
206
|
-
if (value &&
|
|
207
|
-
typeof value === "object" &&
|
|
208
|
-
Object.prototype.hasOwnProperty.call(value, key)) {
|
|
209
|
-
return value[key];
|
|
210
|
-
}
|
|
211
|
-
return undefined;
|
|
212
|
-
}
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
export const workItemKinds = ["task", "plan", "prd", "work"];
|
|
2
|
-
export function normalizeWorkItemAnnotations(input) {
|
|
3
|
-
if (!Array.isArray(input.annotations)) {
|
|
4
|
-
return [];
|
|
5
|
-
}
|
|
6
|
-
const availableKeys = new Set(input.availableWorkItems.map((item) => item.key));
|
|
7
|
-
const seen = new Set();
|
|
8
|
-
const normalized = [];
|
|
9
|
-
for (const annotation of input.annotations) {
|
|
10
|
-
if (!isRecord(annotation) || typeof annotation.key !== "string") {
|
|
11
|
-
continue;
|
|
12
|
-
}
|
|
13
|
-
if (!availableKeys.has(annotation.key) || seen.has(annotation.key)) {
|
|
14
|
-
continue;
|
|
15
|
-
}
|
|
16
|
-
seen.add(annotation.key);
|
|
17
|
-
normalized.push({
|
|
18
|
-
key: annotation.key,
|
|
19
|
-
kind: normalizeWorkItemKind(annotation.kind)
|
|
20
|
-
});
|
|
21
|
-
}
|
|
22
|
-
return normalized;
|
|
23
|
-
}
|
|
24
|
-
export function buildWorkItemKindMap(annotations) {
|
|
25
|
-
return new Map(annotations.map((annotation) => [annotation.key, annotation.kind]));
|
|
26
|
-
}
|
|
27
|
-
export function formatWorkItemChoiceName(input) {
|
|
28
|
-
const kind = input.annotationsByKey.get(input.item.key) ?? "work";
|
|
29
|
-
return `[${kind}] ${input.item.title} (${input.item.key})`;
|
|
30
|
-
}
|
|
31
|
-
function normalizeWorkItemKind(value) {
|
|
32
|
-
return typeof value === "string" && isWorkItemKind(value) ? value : "work";
|
|
33
|
-
}
|
|
34
|
-
function isWorkItemKind(value) {
|
|
35
|
-
return workItemKinds.includes(value);
|
|
36
|
-
}
|
|
37
|
-
function isRecord(value) {
|
|
38
|
-
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
39
|
-
}
|