@applica-software-guru/sdd-core 1.8.1 → 1.8.3
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/dist/agent/agent-defaults.js +2 -2
- package/dist/agent/agent-defaults.js.map +1 -1
- package/dist/agent/agent-runner.d.ts +17 -0
- package/dist/agent/agent-runner.d.ts.map +1 -1
- package/dist/agent/agent-runner.js +163 -11
- package/dist/agent/agent-runner.js.map +1 -1
- package/dist/agent/worker-daemon.d.ts +12 -0
- package/dist/agent/worker-daemon.d.ts.map +1 -0
- package/dist/agent/worker-daemon.js +220 -0
- package/dist/agent/worker-daemon.js.map +1 -0
- package/dist/git/git.d.ts +6 -0
- package/dist/git/git.d.ts.map +1 -1
- package/dist/git/git.js +60 -0
- package/dist/git/git.js.map +1 -1
- package/dist/index.d.ts +8 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +19 -3
- package/dist/index.js.map +1 -1
- package/dist/parser/bug-parser.d.ts.map +1 -1
- package/dist/parser/bug-parser.js +2 -1
- package/dist/parser/bug-parser.js.map +1 -1
- package/dist/parser/cr-parser.d.ts.map +1 -1
- package/dist/parser/cr-parser.js +2 -1
- package/dist/parser/cr-parser.js.map +1 -1
- package/dist/prompt/draft-prompt-generator.d.ts +1 -1
- package/dist/prompt/draft-prompt-generator.d.ts.map +1 -1
- package/dist/prompt/draft-prompt-generator.js +23 -35
- package/dist/prompt/draft-prompt-generator.js.map +1 -1
- package/dist/prompt/prompt-generator.d.ts.map +1 -1
- package/dist/prompt/prompt-generator.js +5 -0
- package/dist/prompt/prompt-generator.js.map +1 -1
- package/dist/remote/api-client.d.ts +2 -2
- package/dist/remote/api-client.d.ts.map +1 -1
- package/dist/remote/api-client.js +4 -4
- package/dist/remote/api-client.js.map +1 -1
- package/dist/remote/sync-engine.d.ts.map +1 -1
- package/dist/remote/sync-engine.js +13 -8
- package/dist/remote/sync-engine.js.map +1 -1
- package/dist/remote/worker-client.d.ts +22 -0
- package/dist/remote/worker-client.d.ts.map +1 -0
- package/dist/remote/worker-client.js +88 -0
- package/dist/remote/worker-client.js.map +1 -0
- package/dist/remote/worker-types.d.ts +38 -0
- package/dist/remote/worker-types.d.ts.map +1 -0
- package/dist/remote/worker-types.js +3 -0
- package/dist/remote/worker-types.js.map +1 -0
- package/dist/scaffold/skill-adapters.d.ts +0 -9
- package/dist/scaffold/skill-adapters.d.ts.map +1 -1
- package/dist/scaffold/skill-adapters.js +17 -0
- package/dist/scaffold/skill-adapters.js.map +1 -1
- package/dist/scaffold/templates.d.ts +1 -5
- package/dist/scaffold/templates.d.ts.map +1 -1
- package/dist/scaffold/templates.generated.d.ts +7 -0
- package/dist/scaffold/templates.generated.d.ts.map +1 -0
- package/dist/scaffold/templates.generated.js +482 -0
- package/dist/scaffold/templates.generated.js.map +1 -0
- package/dist/scaffold/templates.js +8 -338
- package/dist/scaffold/templates.js.map +1 -1
- package/dist/sdd.d.ts +0 -1
- package/dist/sdd.d.ts.map +1 -1
- package/dist/sdd.js +1 -18
- package/dist/sdd.js.map +1 -1
- package/package.json +2 -1
- package/scripts/generate-templates.mjs +38 -0
- package/src/agent/agent-defaults.ts +2 -2
- package/src/agent/agent-runner.ts +184 -12
- package/src/agent/worker-daemon.ts +254 -0
- package/src/git/git.ts +61 -0
- package/src/index.ts +8 -3
- package/src/parser/bug-parser.ts +5 -3
- package/src/parser/cr-parser.ts +5 -3
- package/src/prompt/draft-prompt-generator.ts +26 -38
- package/src/prompt/prompt-generator.ts +8 -0
- package/src/remote/api-client.ts +2 -2
- package/src/remote/sync-engine.ts +16 -15
- package/src/remote/worker-client.ts +141 -0
- package/src/remote/worker-types.ts +40 -0
- package/src/scaffold/skill-adapters.ts +18 -11
- package/src/scaffold/templates.generated.ts +484 -0
- package/src/scaffold/templates.ts +9 -342
- package/src/sdd.ts +1 -19
- package/tests/agent-defaults.test.ts +24 -0
- package/tests/api-client.test.ts +6 -6
- package/tests/draft-prompt.test.ts +78 -0
- package/dist/prompt/apply-prompt-generator.d.ts +0 -4
- package/dist/prompt/apply-prompt-generator.d.ts.map +0 -1
- package/dist/prompt/apply-prompt-generator.js +0 -97
- package/dist/prompt/apply-prompt-generator.js.map +0 -1
- package/src/prompt/apply-prompt-generator.ts +0 -117
- package/tests/apply.test.ts +0 -117
|
@@ -8,67 +8,55 @@ export interface DraftElements {
|
|
|
8
8
|
|
|
9
9
|
export function generateDraftEnrichmentPrompt(
|
|
10
10
|
drafts: DraftElements,
|
|
11
|
-
projectContext: StoryFile[],
|
|
12
|
-
projectDescription: string,
|
|
13
11
|
): string | null {
|
|
14
12
|
const totalDrafts = drafts.docs.length + drafts.crs.length + drafts.bugs.length;
|
|
15
13
|
if (totalDrafts === 0) {
|
|
16
14
|
return null;
|
|
17
15
|
}
|
|
18
16
|
|
|
19
|
-
const sections: string[] = [
|
|
17
|
+
const sections: string[] = [
|
|
18
|
+
'# Draft Tasks',
|
|
19
|
+
'',
|
|
20
|
+
'Enrich all draft elements listed below.',
|
|
21
|
+
'Read each file directly from disk, complete missing details, and save it keeping `status: draft`.',
|
|
22
|
+
'Do not mark statuses automatically in this step.',
|
|
23
|
+
'',
|
|
24
|
+
];
|
|
20
25
|
|
|
21
|
-
// Project context header
|
|
22
|
-
sections.push(`# Draft Enrichment\n`);
|
|
23
|
-
sections.push(`## Project\n\n${projectDescription}\n`);
|
|
24
|
-
|
|
25
|
-
// Global context: all non-draft documents
|
|
26
|
-
if (projectContext.length > 0) {
|
|
27
|
-
const ctxLines = [`## Project context (${projectContext.length} documents)\n`];
|
|
28
|
-
ctxLines.push('Use the following existing documents as context to produce complete, coherent documentation.\n');
|
|
29
|
-
for (const f of projectContext) {
|
|
30
|
-
ctxLines.push(`### \`${f.relativePath}\` — ${f.frontmatter.title}\n`);
|
|
31
|
-
ctxLines.push(f.body.trim());
|
|
32
|
-
ctxLines.push('');
|
|
33
|
-
}
|
|
34
|
-
sections.push(ctxLines.join('\n'));
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// Draft documents
|
|
38
26
|
if (drafts.docs.length > 0) {
|
|
39
|
-
const lines = [`## Draft documents
|
|
40
|
-
lines.push('Each draft below contains incomplete human-written content. Produce a complete version for each document, preserving the original intent while adding missing details based on project context.\n');
|
|
27
|
+
const lines = [`## Draft documents (${drafts.docs.length})`];
|
|
41
28
|
for (const f of drafts.docs) {
|
|
42
|
-
lines.push(
|
|
43
|
-
lines.push(f.body.trim());
|
|
44
|
-
lines.push('');
|
|
29
|
+
lines.push(`- \`${f.relativePath}\` — ${f.frontmatter.title}`);
|
|
45
30
|
}
|
|
46
31
|
sections.push(lines.join('\n'));
|
|
32
|
+
sections.push('');
|
|
47
33
|
}
|
|
48
34
|
|
|
49
|
-
// Draft change requests
|
|
50
35
|
if (drafts.crs.length > 0) {
|
|
51
|
-
const lines = [`## Draft change requests
|
|
52
|
-
lines.push('Each draft CR contains a rough description of requested changes. Produce a complete, actionable change request for each, specifying which documents are affected and what changes should be made.\n');
|
|
36
|
+
const lines = [`## Draft change requests (${drafts.crs.length})`];
|
|
53
37
|
for (const cr of drafts.crs) {
|
|
54
|
-
lines.push(
|
|
55
|
-
lines.push(cr.body.trim());
|
|
56
|
-
lines.push('');
|
|
38
|
+
lines.push(`- \`${cr.relativePath}\` — ${cr.frontmatter.title}`);
|
|
57
39
|
}
|
|
58
40
|
sections.push(lines.join('\n'));
|
|
41
|
+
sections.push('');
|
|
59
42
|
}
|
|
60
43
|
|
|
61
|
-
// Draft bugs
|
|
62
44
|
if (drafts.bugs.length > 0) {
|
|
63
|
-
const lines = [`## Draft bugs
|
|
64
|
-
lines.push('Each draft bug contains a rough description of an issue. Produce a complete bug report for each, including affected components, expected vs actual behavior, and steps to reproduce when possible.\n');
|
|
45
|
+
const lines = [`## Draft bugs (${drafts.bugs.length})`];
|
|
65
46
|
for (const bug of drafts.bugs) {
|
|
66
|
-
lines.push(
|
|
67
|
-
lines.push(bug.body.trim());
|
|
68
|
-
lines.push('');
|
|
47
|
+
lines.push(`- \`${bug.relativePath}\` — ${bug.frontmatter.title}`);
|
|
69
48
|
}
|
|
70
49
|
sections.push(lines.join('\n'));
|
|
50
|
+
sections.push('');
|
|
71
51
|
}
|
|
72
52
|
|
|
73
|
-
|
|
53
|
+
sections.push(
|
|
54
|
+
'## Report\n',
|
|
55
|
+
'At the end of the enrichment, provide a detailed report including:\n' +
|
|
56
|
+
'- List of enriched files (documents, CRs, bugs)\n' +
|
|
57
|
+
'- For each file: what was added or completed\n' +
|
|
58
|
+
'- Any ambiguities resolved or assumptions made'
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
return sections.join('\n');
|
|
74
62
|
}
|
|
@@ -35,5 +35,13 @@ export function generatePrompt(files: StoryFile[], root?: string): string {
|
|
|
35
35
|
sections.push(delLines.join('\n'));
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
sections.push(
|
|
39
|
+
'## Report\n\n' +
|
|
40
|
+
'At the end of your work, provide a detailed report including:\n' +
|
|
41
|
+
'- List of files created, modified, or deleted\n' +
|
|
42
|
+
'- Description of actions taken for each file\n' +
|
|
43
|
+
'- Any issues encountered or decisions made'
|
|
44
|
+
);
|
|
45
|
+
|
|
38
46
|
return sections.join('\n\n');
|
|
39
47
|
}
|
package/src/remote/api-client.ts
CHANGED
|
@@ -180,7 +180,7 @@ export async function pushDocs(
|
|
|
180
180
|
}
|
|
181
181
|
|
|
182
182
|
/** GET /cli/pending-crs */
|
|
183
|
-
export async function
|
|
183
|
+
export async function pullPendingCRs(config: ApiClientConfig): Promise<RemoteCRResponse[]> {
|
|
184
184
|
return request<RemoteCRResponse[]>(config, 'GET', '/cli/pending-crs');
|
|
185
185
|
}
|
|
186
186
|
|
|
@@ -193,7 +193,7 @@ export async function pushCRs(
|
|
|
193
193
|
}
|
|
194
194
|
|
|
195
195
|
/** GET /cli/open-bugs */
|
|
196
|
-
export async function
|
|
196
|
+
export async function pullOpenBugs(config: ApiClientConfig): Promise<RemoteBugResponse[]> {
|
|
197
197
|
return request<RemoteBugResponse[]>(config, 'GET', '/cli/open-bugs');
|
|
198
198
|
}
|
|
199
199
|
|
|
@@ -8,7 +8,7 @@ import { readConfig } from '../config/config-manager.js';
|
|
|
8
8
|
import { parseAllStoryFiles } from '../parser/story-parser.js';
|
|
9
9
|
import { parseAllCRFiles } from '../parser/cr-parser.js';
|
|
10
10
|
import { parseAllBugFiles } from '../parser/bug-parser.js';
|
|
11
|
-
import { buildApiConfig, pullDocs, pushDocs, pushCRs, pushBugs, deleteDocs, deleteCRs, deleteBugs,
|
|
11
|
+
import { buildApiConfig, pullDocs, pushDocs, pushCRs, pushBugs, deleteDocs, deleteCRs, deleteBugs, pullPendingCRs, pullOpenBugs, resetProject } from './api-client.js';
|
|
12
12
|
import { readRemoteState, writeRemoteState } from './state.js';
|
|
13
13
|
import type {
|
|
14
14
|
PushResult,
|
|
@@ -139,6 +139,7 @@ export async function pushToRemote(root: string, options?: PushOptions): Promise
|
|
|
139
139
|
path: normalizePath(f.relativePath),
|
|
140
140
|
title: f.frontmatter.title,
|
|
141
141
|
content: f.body,
|
|
142
|
+
status: f.frontmatter.status,
|
|
142
143
|
}));
|
|
143
144
|
|
|
144
145
|
const result = await pushDocs(api, documents);
|
|
@@ -194,13 +195,13 @@ export async function pushToRemote(root: string, options?: PushOptions): Promise
|
|
|
194
195
|
const crResult = await pushCRs(api, crPayload);
|
|
195
196
|
|
|
196
197
|
for (const cr of crResult.change_requests) {
|
|
197
|
-
const localPath =
|
|
198
|
-
(f) => f.frontmatter.title === cr.title
|
|
199
|
-
)?.relativePath;
|
|
198
|
+
const localPath = cr.path
|
|
199
|
+
?? crsToPush.find((f) => f.frontmatter.title === cr.title)?.relativePath;
|
|
200
200
|
if (localPath) {
|
|
201
|
-
const
|
|
201
|
+
const normalized = normalizePath(localPath);
|
|
202
|
+
const absPath = resolve(root, normalized);
|
|
202
203
|
const rawContent = existsSync(absPath) ? await readFile(absPath, 'utf-8') : '';
|
|
203
|
-
state.changeRequests![
|
|
204
|
+
state.changeRequests![normalized] = {
|
|
204
205
|
remoteId: cr.id,
|
|
205
206
|
localHash: sha256(rawContent),
|
|
206
207
|
lastSynced: new Date().toISOString(),
|
|
@@ -247,13 +248,13 @@ export async function pushToRemote(root: string, options?: PushOptions): Promise
|
|
|
247
248
|
const bugResult = await pushBugs(api, bugPayload);
|
|
248
249
|
|
|
249
250
|
for (const bug of bugResult.bugs) {
|
|
250
|
-
const localPath =
|
|
251
|
-
(b) => b.frontmatter.title === bug.title
|
|
252
|
-
)?.relativePath;
|
|
251
|
+
const localPath = bug.path
|
|
252
|
+
?? bugsToPush.find((b) => b.frontmatter.title === bug.title)?.relativePath;
|
|
253
253
|
if (localPath) {
|
|
254
|
-
const
|
|
254
|
+
const normalized = normalizePath(localPath);
|
|
255
|
+
const absPath = resolve(root, normalized);
|
|
255
256
|
const rawContent = existsSync(absPath) ? await readFile(absPath, 'utf-8') : '';
|
|
256
|
-
state.bugs![
|
|
257
|
+
state.bugs![normalized] = {
|
|
257
258
|
remoteId: bug.id,
|
|
258
259
|
localHash: sha256(rawContent),
|
|
259
260
|
lastSynced: new Date().toISOString(),
|
|
@@ -432,7 +433,7 @@ export async function pullCRsFromRemote(root: string, timeout?: number): Promise
|
|
|
432
433
|
const config = await readConfig(root);
|
|
433
434
|
const api = buildApiConfig(config, timeout);
|
|
434
435
|
|
|
435
|
-
const remoteCRs = await
|
|
436
|
+
const remoteCRs = await pullPendingCRs(api);
|
|
436
437
|
const state = await readRemoteState(root);
|
|
437
438
|
if (!state.changeRequests) state.changeRequests = {};
|
|
438
439
|
|
|
@@ -448,7 +449,7 @@ export async function pullCRsFromRemote(root: string, timeout?: number): Promise
|
|
|
448
449
|
|
|
449
450
|
// Detect remote deletions: tracked locally but not in remote response
|
|
450
451
|
const remoteCRIdSet = new Set(remoteCRs.map((cr) => cr.id));
|
|
451
|
-
for (const [localPath, tracked] of Object.entries(state.changeRequests
|
|
452
|
+
for (const [localPath, tracked] of Object.entries(state.changeRequests)) {
|
|
452
453
|
if (!remoteCRIdSet.has(tracked.remoteId)) {
|
|
453
454
|
const absPath = resolve(root, localPath);
|
|
454
455
|
if (existsSync(absPath)) {
|
|
@@ -522,7 +523,7 @@ export async function pullBugsFromRemote(root: string, timeout?: number): Promis
|
|
|
522
523
|
const config = await readConfig(root);
|
|
523
524
|
const api = buildApiConfig(config, timeout);
|
|
524
525
|
|
|
525
|
-
const remoteBugs = await
|
|
526
|
+
const remoteBugs = await pullOpenBugs(api);
|
|
526
527
|
const state = await readRemoteState(root);
|
|
527
528
|
if (!state.bugs) state.bugs = {};
|
|
528
529
|
|
|
@@ -538,7 +539,7 @@ export async function pullBugsFromRemote(root: string, timeout?: number): Promis
|
|
|
538
539
|
|
|
539
540
|
// Detect remote deletions: tracked locally but not in remote response
|
|
540
541
|
const remoteBugIdSet = new Set(remoteBugs.map((b) => b.id));
|
|
541
|
-
for (const [localPath, tracked] of Object.entries(state.bugs
|
|
542
|
+
for (const [localPath, tracked] of Object.entries(state.bugs)) {
|
|
542
543
|
if (!remoteBugIdSet.has(tracked.remoteId)) {
|
|
543
544
|
const absPath = resolve(root, localPath);
|
|
544
545
|
if (existsSync(absPath)) {
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import type { ApiClientConfig } from './api-client.js';
|
|
2
|
+
import type { WorkerRegistration, WorkerJobAssignment, WorkerJobAnswer } from './worker-types.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Low-level fetch wrapper for worker endpoints.
|
|
6
|
+
* Unlike the main api-client, worker requests have different timeout needs
|
|
7
|
+
* (e.g. long-poll uses 35s timeout) and don't need full retry logic.
|
|
8
|
+
*/
|
|
9
|
+
async function workerRequest<T>(
|
|
10
|
+
config: ApiClientConfig,
|
|
11
|
+
method: string,
|
|
12
|
+
path: string,
|
|
13
|
+
body?: unknown,
|
|
14
|
+
timeoutMs?: number,
|
|
15
|
+
): Promise<T> {
|
|
16
|
+
const url = `${config.baseUrl}${path}`;
|
|
17
|
+
const controller = new AbortController();
|
|
18
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs ?? 10_000);
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
const res = await fetch(url, {
|
|
22
|
+
method,
|
|
23
|
+
headers: {
|
|
24
|
+
Authorization: `Bearer ${config.apiKey}`,
|
|
25
|
+
'Content-Type': 'application/json',
|
|
26
|
+
},
|
|
27
|
+
body: body != null ? JSON.stringify(body) : undefined,
|
|
28
|
+
signal: controller.signal,
|
|
29
|
+
});
|
|
30
|
+
clearTimeout(timer);
|
|
31
|
+
|
|
32
|
+
if (!res.ok) {
|
|
33
|
+
let detail: string;
|
|
34
|
+
try {
|
|
35
|
+
const err = (await res.json()) as { detail?: string };
|
|
36
|
+
detail = err.detail ?? res.statusText;
|
|
37
|
+
} catch {
|
|
38
|
+
detail = res.statusText;
|
|
39
|
+
}
|
|
40
|
+
throw new Error(`Worker API error ${res.status}: ${detail}`);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// 204 No Content (poll with no job)
|
|
44
|
+
if (res.status === 204) {
|
|
45
|
+
return null as T;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return (await res.json()) as T;
|
|
49
|
+
} catch (error) {
|
|
50
|
+
clearTimeout(timer);
|
|
51
|
+
throw error;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** POST /cli/workers/register */
|
|
56
|
+
export async function registerWorker(
|
|
57
|
+
config: ApiClientConfig,
|
|
58
|
+
name: string,
|
|
59
|
+
agent: string,
|
|
60
|
+
branch?: string,
|
|
61
|
+
metadata?: Record<string, unknown>,
|
|
62
|
+
): Promise<WorkerRegistration> {
|
|
63
|
+
return workerRequest<WorkerRegistration>(
|
|
64
|
+
config, 'POST', '/cli/workers/register',
|
|
65
|
+
{ name, agent, branch, metadata },
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** POST /cli/workers/:workerId/heartbeat */
|
|
70
|
+
export async function workerHeartbeat(
|
|
71
|
+
config: ApiClientConfig,
|
|
72
|
+
workerId: string,
|
|
73
|
+
workerStatus: 'online' | 'busy' = 'online',
|
|
74
|
+
): Promise<void> {
|
|
75
|
+
await workerRequest(
|
|
76
|
+
config, 'POST', `/cli/workers/${workerId}/heartbeat`,
|
|
77
|
+
{ status: workerStatus },
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** GET /cli/workers/:workerId/poll — long-poll (up to 35s timeout) */
|
|
82
|
+
export async function workerPoll(
|
|
83
|
+
config: ApiClientConfig,
|
|
84
|
+
workerId: string,
|
|
85
|
+
): Promise<WorkerJobAssignment | null> {
|
|
86
|
+
return workerRequest<WorkerJobAssignment | null>(
|
|
87
|
+
config, 'GET', `/cli/workers/${workerId}/poll`,
|
|
88
|
+
undefined,
|
|
89
|
+
35_000, // 35s to exceed server's 30s hold time
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** POST /cli/workers/jobs/:jobId/started */
|
|
94
|
+
export async function workerJobStarted(
|
|
95
|
+
config: ApiClientConfig,
|
|
96
|
+
jobId: string,
|
|
97
|
+
): Promise<void> {
|
|
98
|
+
await workerRequest(config, 'POST', `/cli/workers/jobs/${jobId}/started`);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** POST /cli/workers/jobs/:jobId/output */
|
|
102
|
+
export async function workerJobOutput(
|
|
103
|
+
config: ApiClientConfig,
|
|
104
|
+
jobId: string,
|
|
105
|
+
lines: string[],
|
|
106
|
+
): Promise<void> {
|
|
107
|
+
await workerRequest(config, 'POST', `/cli/workers/jobs/${jobId}/output`, { lines });
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** POST /cli/workers/jobs/:jobId/question */
|
|
111
|
+
export async function workerJobQuestion(
|
|
112
|
+
config: ApiClientConfig,
|
|
113
|
+
jobId: string,
|
|
114
|
+
content: string,
|
|
115
|
+
): Promise<void> {
|
|
116
|
+
await workerRequest(config, 'POST', `/cli/workers/jobs/${jobId}/question`, { content });
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/** GET /cli/workers/jobs/:jobId/answers?after_sequence=N */
|
|
120
|
+
export async function workerJobAnswers(
|
|
121
|
+
config: ApiClientConfig,
|
|
122
|
+
jobId: string,
|
|
123
|
+
afterSequence: number = 0,
|
|
124
|
+
): Promise<WorkerJobAnswer[]> {
|
|
125
|
+
return workerRequest<WorkerJobAnswer[]>(
|
|
126
|
+
config, 'GET', `/cli/workers/jobs/${jobId}/answers?after_sequence=${afterSequence}`,
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/** POST /cli/workers/jobs/:jobId/completed */
|
|
131
|
+
export async function workerJobCompleted(
|
|
132
|
+
config: ApiClientConfig,
|
|
133
|
+
jobId: string,
|
|
134
|
+
exitCode: number,
|
|
135
|
+
changedFiles?: Array<{ path: string; status: 'new' | 'modified' | 'deleted' }>,
|
|
136
|
+
): Promise<void> {
|
|
137
|
+
await workerRequest(config, 'POST', `/cli/workers/jobs/${jobId}/completed`, {
|
|
138
|
+
exit_code: exitCode,
|
|
139
|
+
changed_files: changedFiles ?? [],
|
|
140
|
+
});
|
|
141
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/** Worker registration response from the server */
|
|
2
|
+
export interface WorkerRegistration {
|
|
3
|
+
id: string;
|
|
4
|
+
project_id: string;
|
|
5
|
+
name: string;
|
|
6
|
+
status: string;
|
|
7
|
+
agent: string;
|
|
8
|
+
branch?: string;
|
|
9
|
+
last_heartbeat_at: string | null;
|
|
10
|
+
registered_at: string;
|
|
11
|
+
is_online: boolean;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/** Job assignment returned by the poll endpoint */
|
|
15
|
+
export interface WorkerJobAssignment {
|
|
16
|
+
job_id: string;
|
|
17
|
+
entity_type: string | null;
|
|
18
|
+
entity_id: string | null;
|
|
19
|
+
prompt: string;
|
|
20
|
+
agent: string;
|
|
21
|
+
model?: string;
|
|
22
|
+
branch?: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** Answer message from the user */
|
|
26
|
+
export interface WorkerJobAnswer {
|
|
27
|
+
id: string;
|
|
28
|
+
job_id: string;
|
|
29
|
+
kind: 'answer';
|
|
30
|
+
content: string;
|
|
31
|
+
sequence: number;
|
|
32
|
+
created_at: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Local worker state persisted in .sdd/worker.json */
|
|
36
|
+
export interface WorkerState {
|
|
37
|
+
workerId: string;
|
|
38
|
+
name: string;
|
|
39
|
+
registeredAt: string;
|
|
40
|
+
}
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
CHANGE_REQUESTS_REFERENCE,
|
|
7
7
|
FILE_FORMAT_REFERENCE,
|
|
8
8
|
SKILL_MD_TEMPLATE,
|
|
9
|
+
SKILL_REMOTE_MD_TEMPLATE,
|
|
9
10
|
SKILL_UI_MD_TEMPLATE,
|
|
10
11
|
} from "./templates.js";
|
|
11
12
|
|
|
@@ -81,22 +82,20 @@ const CANONICAL_SKILLS: Array<{
|
|
|
81
82
|
},
|
|
82
83
|
],
|
|
83
84
|
},
|
|
85
|
+
{
|
|
86
|
+
id: "sdd-remote",
|
|
87
|
+
files: [
|
|
88
|
+
{
|
|
89
|
+
path: `${CANONICAL_BASE_DIR}/sdd-remote/SKILL.md`,
|
|
90
|
+
content: SKILL_REMOTE_MD_TEMPLATE,
|
|
91
|
+
},
|
|
92
|
+
],
|
|
93
|
+
},
|
|
84
94
|
];
|
|
85
95
|
|
|
86
96
|
const CANONICAL_FILES: Array<{ path: string; content: string }> =
|
|
87
97
|
CANONICAL_SKILLS.flatMap((skill) => skill.files);
|
|
88
98
|
|
|
89
|
-
export interface SkillPathsDefinition {
|
|
90
|
-
skillId: string;
|
|
91
|
-
paths: string[];
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
export interface SkillAdapterDefinition {
|
|
95
|
-
id: string;
|
|
96
|
-
mode: AdapterMode;
|
|
97
|
-
skills: SkillPathsDefinition[];
|
|
98
|
-
}
|
|
99
|
-
|
|
100
99
|
export const SKILL_ADAPTERS: SkillAdapterDefinition[] = [
|
|
101
100
|
{
|
|
102
101
|
id: "claude",
|
|
@@ -115,6 +114,10 @@ export const SKILL_ADAPTERS: SkillAdapterDefinition[] = [
|
|
|
115
114
|
skillId: "sdd-ui",
|
|
116
115
|
paths: [".claude/skills/sdd-ui/SKILL.md"],
|
|
117
116
|
},
|
|
117
|
+
{
|
|
118
|
+
skillId: "sdd-remote",
|
|
119
|
+
paths: [".claude/skills/sdd-remote/SKILL.md"],
|
|
120
|
+
},
|
|
118
121
|
],
|
|
119
122
|
},
|
|
120
123
|
{
|
|
@@ -134,6 +137,10 @@ export const SKILL_ADAPTERS: SkillAdapterDefinition[] = [
|
|
|
134
137
|
skillId: "sdd-ui",
|
|
135
138
|
paths: [".agents/skills/sdd-ui/SKILL.md"],
|
|
136
139
|
},
|
|
140
|
+
{
|
|
141
|
+
skillId: "sdd-remote",
|
|
142
|
+
paths: [".agents/skills/sdd-remote/SKILL.md"],
|
|
143
|
+
},
|
|
137
144
|
],
|
|
138
145
|
},
|
|
139
146
|
];
|