@ddtcorex/dsh-maestro-review 0.11.1 → 0.12.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 +2 -3
- package/lib/client.js +10 -1
- package/lib/config-store.d.ts +0 -8
- package/lib/config-store.d.ts.map +1 -1
- package/lib/config-store.js +0 -3
- package/lib/config-store.js.map +1 -1
- package/lib/hyva-theme-inspect-tool.js.map +1 -1
- package/lib/layout-xml-tool.d.ts.map +1 -1
- package/lib/layout-xml-tool.js +0 -1
- package/lib/layout-xml-tool.js.map +1 -1
- package/lib/module-check-tool.d.ts.map +1 -1
- package/lib/module-check-tool.js +0 -1
- package/lib/module-check-tool.js.map +1 -1
- package/lib/notify.d.ts +0 -1
- package/lib/notify.d.ts.map +1 -1
- package/lib/notify.js +0 -3
- package/lib/notify.js.map +1 -1
- package/lib/orchestrator.d.ts +1 -9
- package/lib/orchestrator.d.ts.map +1 -1
- package/lib/orchestrator.js +1 -14
- package/lib/orchestrator.js.map +1 -1
- package/lib/phtml-escape-scan-tool.d.ts.map +1 -1
- package/lib/phtml-escape-scan-tool.js +0 -4
- package/lib/phtml-escape-scan-tool.js.map +1 -1
- package/lib/providers/gitlab.d.ts +0 -2
- package/lib/providers/gitlab.d.ts.map +1 -1
- package/lib/providers/gitlab.js +0 -34
- package/lib/providers/gitlab.js.map +1 -1
- package/lib/scope-split-tool.d.ts.map +1 -1
- package/lib/scope-split-tool.js +0 -1
- package/lib/scope-split-tool.js.map +1 -1
- package/lib/settings-rpc.d.ts.map +1 -1
- package/lib/settings-rpc.js.map +1 -1
- package/lib/types/client/BrandMark.d.ts +0 -3
- package/lib/types/client/BrandMark.d.ts.map +1 -1
- package/lib/types/client/review/styles.d.ts +1 -1
- package/lib/types/client/review/styles.d.ts.map +1 -1
- package/package.json +3 -4
- package/presets/maestro-auditor.patch.yml +6 -6
- package/presets/maestro-coder/agent.cordis.yml +5 -8
- package/presets/maestro-reviewer.patch.yml +6 -6
- package/skills/dsh-native-tools/SKILL.md +0 -3
- package/src/client/BrandMark.tsx +1 -1
- package/src/client/review/styles.ts +10 -1
- package/src/host/config-store.ts +0 -4
- package/src/host/hyva-theme-inspect-tool.ts +1 -1
- package/src/host/layout-xml-tool.ts +1 -2
- package/src/host/module-check-tool.ts +1 -2
- package/src/host/notify.ts +0 -4
- package/src/host/orchestrator.ts +1 -17
- package/src/host/phtml-escape-scan-tool.ts +0 -5
- package/src/host/providers/gitlab.ts +0 -35
- package/src/host/scope-split-tool.ts +0 -1
- package/src/host/settings-rpc.ts +0 -1
- package/client/settings-card.tsx +0 -4
- package/lib/git-worktree-tool.d.ts +0 -11
- package/lib/git-worktree-tool.d.ts.map +0 -1
- package/lib/git-worktree-tool.js +0 -162
- package/lib/git-worktree-tool.js.map +0 -1
- package/lib/plan-track-tool.d.ts +0 -11
- package/lib/plan-track-tool.d.ts.map +0 -1
- package/lib/plan-track-tool.js +0 -143
- package/lib/plan-track-tool.js.map +0 -1
- package/lib/providers/github.stub.d.ts +0 -3
- package/lib/providers/github.stub.d.ts.map +0 -1
- package/lib/providers/github.stub.js +0 -10
- package/lib/providers/github.stub.js.map +0 -1
- package/lib/providers/interface.d.ts +0 -12
- package/lib/providers/interface.d.ts.map +0 -1
- package/lib/providers/interface.js +0 -2
- package/lib/providers/interface.js.map +0 -1
- package/lib/tdd-evidence-tool.d.ts +0 -11
- package/lib/tdd-evidence-tool.d.ts.map +0 -1
- package/lib/tdd-evidence-tool.js +0 -114
- package/lib/tdd-evidence-tool.js.map +0 -1
- package/lib/webhook-secret.d.ts +0 -31
- package/lib/webhook-secret.d.ts.map +0 -1
- package/lib/webhook-secret.js +0 -38
- package/lib/webhook-secret.js.map +0 -1
- package/src/host/git-worktree-tool.ts +0 -130
- package/src/host/plan-track-tool.ts +0 -118
- package/src/host/providers/github.stub.ts +0 -11
- package/src/host/providers/interface.ts +0 -2
- package/src/host/tdd-evidence-tool.ts +0 -85
- package/src/host/webhook-secret.ts +0 -43
package/lib/plan-track-tool.js
DELETED
|
@@ -1,143 +0,0 @@
|
|
|
1
|
-
import { join, resolve, sep } from 'node:path';
|
|
2
|
-
import { readFile, writeFile, mkdir, realpath } from 'node:fs/promises';
|
|
3
|
-
import { defineTool } from '@deepseek-ai/dsh-tools';
|
|
4
|
-
import z from '@deepseek-ai/schemastery';
|
|
5
|
-
export const name = 'maestro-plan-track-tool';
|
|
6
|
-
export const inject = ['tools'];
|
|
7
|
-
export const Config = z.object({ rootPath: z.string() });
|
|
8
|
-
function workspaceRootFor(c, e) { if (c !== undefined)
|
|
9
|
-
return c; const cwd = e?.agent?.session?.header?.cwd; return typeof cwd === 'string' && cwd !== '' ? cwd : process.cwd(); }
|
|
10
|
-
async function isInsideRoot(r, t) {
|
|
11
|
-
const ar = resolve(r);
|
|
12
|
-
const rs = resolve(ar, t);
|
|
13
|
-
if (rs !== ar && !rs.startsWith(ar + sep))
|
|
14
|
-
return false;
|
|
15
|
-
try {
|
|
16
|
-
const rr = await realpath(ar);
|
|
17
|
-
const rt = await realpath(rs);
|
|
18
|
-
return rt === rr || rt.startsWith(rr + sep);
|
|
19
|
-
}
|
|
20
|
-
catch {
|
|
21
|
-
try {
|
|
22
|
-
const rr = await realpath(ar);
|
|
23
|
-
const parent = resolve(rs, '..');
|
|
24
|
-
const rp = await realpath(parent);
|
|
25
|
-
return rp === rr || rp.startsWith(rr + sep);
|
|
26
|
-
}
|
|
27
|
-
catch {
|
|
28
|
-
return rs === ar || rs.startsWith(ar + sep);
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
function parseTasks(md) {
|
|
33
|
-
const lines = md.split('\n');
|
|
34
|
-
const tasks = [];
|
|
35
|
-
for (let i = 0; i < lines.length; i++) {
|
|
36
|
-
const m = /^###\s+(Task\s*\d+):?\s*(.*)/.exec(lines[i].trim());
|
|
37
|
-
if (!m)
|
|
38
|
-
continue;
|
|
39
|
-
const id = m[1].trim();
|
|
40
|
-
let title = m[2].trim();
|
|
41
|
-
let status = 'pending';
|
|
42
|
-
if (title.includes('in_progress'))
|
|
43
|
-
status = 'in_progress';
|
|
44
|
-
else if (title.toLowerCase().includes('done') || title.includes('✅'))
|
|
45
|
-
status = 'done';
|
|
46
|
-
else if (title.toLowerCase().includes('blocked'))
|
|
47
|
-
status = 'blocked';
|
|
48
|
-
for (let j = i + 1; j < Math.min(i + 4, lines.length); j++) {
|
|
49
|
-
if (lines[j].toLowerCase().includes('in_progress'))
|
|
50
|
-
status = 'in_progress';
|
|
51
|
-
if (lines[j].toLowerCase().includes('status: done'))
|
|
52
|
-
status = 'done';
|
|
53
|
-
}
|
|
54
|
-
tasks.push({ id, title, status, line: i });
|
|
55
|
-
}
|
|
56
|
-
return tasks;
|
|
57
|
-
}
|
|
58
|
-
export function apply(ctx, config = {}) {
|
|
59
|
-
const configuredRoot = config.rootPath;
|
|
60
|
-
ctx.effect(() => ctx.tools.register(defineTool({
|
|
61
|
-
name: 'maestro_plan_track',
|
|
62
|
-
description: 'Track cross-repo plan: init/update/complete tasks with dtodo sync and oneTaskOneCommit guard.',
|
|
63
|
-
parameters: {
|
|
64
|
-
op: { type: 'string', enum: ['init', 'update', 'complete'], required: true },
|
|
65
|
-
planPath: { type: 'string', required: true },
|
|
66
|
-
taskId: { type: 'string' },
|
|
67
|
-
status: { type: 'string', enum: ['pending', 'in_progress', 'done', 'blocked'] },
|
|
68
|
-
note: { type: 'string' },
|
|
69
|
-
},
|
|
70
|
-
output: {
|
|
71
|
-
schema: {
|
|
72
|
-
type: 'object', additionalProperties: true,
|
|
73
|
-
properties: {
|
|
74
|
-
ok: { type: 'boolean', required: true },
|
|
75
|
-
plan: { type: 'object', required: true, additionalProperties: true },
|
|
76
|
-
discipline: { type: 'object', additionalProperties: true },
|
|
77
|
-
}
|
|
78
|
-
},
|
|
79
|
-
render: (_a, v) => [{ type: 'text', text: v.ok ? 'ok' : 'violation' }],
|
|
80
|
-
},
|
|
81
|
-
async execute(args, exec) {
|
|
82
|
-
const op = args.op;
|
|
83
|
-
const rawPath = args.planPath;
|
|
84
|
-
const root = workspaceRootFor(configuredRoot, exec);
|
|
85
|
-
if (!(await isInsideRoot(root, rawPath)))
|
|
86
|
-
return { text: `Path "${rawPath}" escapes the workspace root.`, truncated: false };
|
|
87
|
-
const planPath = resolve(root, rawPath);
|
|
88
|
-
let md = '';
|
|
89
|
-
try {
|
|
90
|
-
md = await readFile(planPath, 'utf-8');
|
|
91
|
-
}
|
|
92
|
-
catch {
|
|
93
|
-
if (op === 'init')
|
|
94
|
-
return { text: `plan not found ${rawPath}`, truncated: false };
|
|
95
|
-
md = '';
|
|
96
|
-
}
|
|
97
|
-
const tasks = parseTasks(md);
|
|
98
|
-
const lines = md.split('\n');
|
|
99
|
-
if (op === 'init') {
|
|
100
|
-
const nextTask = tasks.find(t => t.status === 'pending' || t.status === 'in_progress') || tasks[0] || null;
|
|
101
|
-
const dtodoPayload = tasks.map(t => ({ content: `${t.id}: ${t.title}`, status: t.status }));
|
|
102
|
-
return { ok: true, plan: { path: rawPath, tasks, nextTask, dtodoPayload }, discipline: { violation: null } };
|
|
103
|
-
}
|
|
104
|
-
if (op === 'update') {
|
|
105
|
-
const taskId = args.taskId;
|
|
106
|
-
const status = args.status;
|
|
107
|
-
if (!taskId)
|
|
108
|
-
return { text: 'taskId required', truncated: false };
|
|
109
|
-
const idx = tasks.findIndex(t => t.id === taskId);
|
|
110
|
-
if (idx < 0)
|
|
111
|
-
return { text: `task ${taskId} not found`, truncated: false };
|
|
112
|
-
if (status === 'in_progress') {
|
|
113
|
-
const other = tasks.find(t => t.id !== taskId && t.status === 'in_progress');
|
|
114
|
-
if (other) {
|
|
115
|
-
return { ok: false, plan: { path: rawPath, tasks, nextTask: tasks.find(t => t.status === 'in_progress') || null, dtodoPayload: [] }, discipline: { violation: 'oneTaskOneCommit: only one task may be in_progress at a time' } };
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
const lineIdx = tasks[idx].line;
|
|
119
|
-
if (status) {
|
|
120
|
-
const orig = lines[lineIdx];
|
|
121
|
-
if (orig.includes('—'))
|
|
122
|
-
lines[lineIdx] = orig.replace(/—.*$/, `— ${status}`);
|
|
123
|
-
else
|
|
124
|
-
lines[lineIdx] = `${orig} — ${status}`;
|
|
125
|
-
await mkdir(join(planPath, '..'), { recursive: true });
|
|
126
|
-
await writeFile(planPath, lines.join('\n'), 'utf-8');
|
|
127
|
-
tasks[idx].status = status;
|
|
128
|
-
}
|
|
129
|
-
const nextTask = tasks.find(t => t.status === 'in_progress') || tasks.find(t => t.status === 'pending') || null;
|
|
130
|
-
return { ok: true, plan: { path: rawPath, tasks, nextTask, dtodoPayload: tasks.map(t => ({ content: `${t.id}: ${t.title}`, status: t.status })) }, discipline: { violation: null } };
|
|
131
|
-
}
|
|
132
|
-
if (op === 'complete') {
|
|
133
|
-
const pending = tasks.filter(t => t.status !== 'done');
|
|
134
|
-
if (pending.length > 0) {
|
|
135
|
-
return { ok: false, plan: { path: rawPath, tasks, nextTask: pending[0], dtodoPayload: [] }, discipline: { violation: `pending tasks remain: ${pending.map(p => p.id).join(',')}` } };
|
|
136
|
-
}
|
|
137
|
-
return { ok: true, plan: { path: rawPath, tasks, nextTask: null, dtodoPayload: [] }, discipline: { violation: null } };
|
|
138
|
-
}
|
|
139
|
-
return { text: `unknown op ${op}`, truncated: false };
|
|
140
|
-
}
|
|
141
|
-
}), 'plan track'));
|
|
142
|
-
}
|
|
143
|
-
//# sourceMappingURL=plan-track-tool.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"plan-track-tool.js","sourceRoot":"","sources":["../src/host/plan-track-tool.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"github.stub.d.ts","sourceRoot":"","sources":["../../src/host/providers/github.stub.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAiB,MAAM,gBAAgB,CAAA;AAEnE,eAAO,MAAM,cAAc,EAAE,cAQ5B,CAAA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"github.stub.js","sourceRoot":"","sources":["../../src/host/providers/github.stub.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,cAAc,GAAmB;IAC5C,EAAE,EAAE,QAAQ;IACZ,KAAK,CAAC,MAAM,CAAC,IAAa;QACxB,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAA;IAC3C,CAAC;IACD,KAAK,CAAC,YAAY,CAAC,SAAgB;QACjC,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAA;IACpC,CAAC;CACF,CAAA"}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
export interface ReviewRequest {
|
|
2
|
-
provider: string;
|
|
3
|
-
projectPath: string;
|
|
4
|
-
mrId: string;
|
|
5
|
-
profile: 'magento2' | 'generic' | 'laravel' | 'custom';
|
|
6
|
-
}
|
|
7
|
-
export interface ReviewProvider {
|
|
8
|
-
id: string;
|
|
9
|
-
intake(req: Request): Promise<ReviewRequest>;
|
|
10
|
-
postFindings(f: any[]): Promise<void>;
|
|
11
|
-
}
|
|
12
|
-
//# sourceMappingURL=interface.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"interface.d.ts","sourceRoot":"","sources":["../../src/host/providers/interface.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAAG,QAAQ,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,UAAU,GAAC,SAAS,GAAC,SAAS,GAAC,QAAQ,CAAC;CAAE;AACzI,MAAM,WAAW,cAAc;IAAG,EAAE,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IAAC,YAAY,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAAE"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"interface.js","sourceRoot":"","sources":["../../src/host/providers/interface.ts"],"names":[],"mappings":""}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import type { Context } from '@deepseek-ai/cordis';
|
|
2
|
-
import z from '@deepseek-ai/schemastery';
|
|
3
|
-
export declare const name = "maestro-tdd-evidence-tool";
|
|
4
|
-
export declare const inject: string[];
|
|
5
|
-
export declare const Config: z<{
|
|
6
|
-
rootPath?: string;
|
|
7
|
-
}>;
|
|
8
|
-
export declare function apply(ctx: Context, config?: {
|
|
9
|
-
rootPath?: string;
|
|
10
|
-
}): void;
|
|
11
|
-
//# sourceMappingURL=tdd-evidence-tool.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"tdd-evidence-tool.d.ts","sourceRoot":"","sources":["../src/host/tdd-evidence-tool.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAElD,OAAO,CAAC,MAAM,0BAA0B,CAAA;AAExC,eAAO,MAAM,IAAI,8BAA4B,CAAA;AAC7C,eAAO,MAAM,MAAM,UAAU,CAAA;AAC7B,eAAO,MAAM,MAAM,EAAC,CAAC,CAAC;IAAC,QAAQ,CAAC,EAAC,MAAM,CAAA;CAAC,CAAmC,CAAA;AAY3E,wBAAgB,KAAK,CAAC,GAAG,EAAC,OAAO,EAAE,MAAM,GAAC;IAAC,QAAQ,CAAC,EAAC,MAAM,CAAA;CAAI,GAAE,IAAI,CA8DpE"}
|
package/lib/tdd-evidence-tool.js
DELETED
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
import { resolve, sep } from 'node:path';
|
|
2
|
-
import { readFile, stat, realpath } from 'node:fs/promises';
|
|
3
|
-
import { execFile } from 'node:child_process';
|
|
4
|
-
import { promisify } from 'node:util';
|
|
5
|
-
import { defineTool } from '@deepseek-ai/dsh-tools';
|
|
6
|
-
import z from '@deepseek-ai/schemastery';
|
|
7
|
-
export const name = 'maestro-tdd-evidence-tool';
|
|
8
|
-
export const inject = ['tools'];
|
|
9
|
-
export const Config = z.object({ rootPath: z.string() });
|
|
10
|
-
function workspaceRootFor(c, e) { if (c !== undefined)
|
|
11
|
-
return c; const cwd = e?.agent?.session?.header?.cwd; return typeof cwd === 'string' && cwd !== '' ? cwd : process.cwd(); }
|
|
12
|
-
async function isInsideRoot(r, t) {
|
|
13
|
-
const ar = resolve(r);
|
|
14
|
-
const rs = resolve(ar, t);
|
|
15
|
-
if (rs !== ar && !rs.startsWith(ar + sep))
|
|
16
|
-
return false;
|
|
17
|
-
try {
|
|
18
|
-
const rr = await realpath(ar);
|
|
19
|
-
const rt = await realpath(rs);
|
|
20
|
-
return rt === rr || rt.startsWith(rr + sep);
|
|
21
|
-
}
|
|
22
|
-
catch {
|
|
23
|
-
try {
|
|
24
|
-
const rr = await realpath(ar);
|
|
25
|
-
const parent = resolve(rs, '..');
|
|
26
|
-
const rp = await realpath(parent);
|
|
27
|
-
return rp === rr || rp.startsWith(rr + sep);
|
|
28
|
-
}
|
|
29
|
-
catch {
|
|
30
|
-
return rs === ar || rs.startsWith(ar + sep);
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
const execFileAsync = promisify(execFile);
|
|
35
|
-
export function apply(ctx, config = {}) {
|
|
36
|
-
const configuredRoot = config.rootPath;
|
|
37
|
-
// simple in-memory red evidence store per process
|
|
38
|
-
const redEvidence = new Set();
|
|
39
|
-
ctx.effect(() => ctx.tools.register(defineTool({
|
|
40
|
-
name: 'maestro_tdd_evidence',
|
|
41
|
-
description: 'Capture TDD evidence: red (failing test), green (passing), verify (pnpm verify). Enforces red-before-green.',
|
|
42
|
-
parameters: {
|
|
43
|
-
op: { type: 'string', enum: ['red', 'green', 'verify'], required: true },
|
|
44
|
-
testFile: { type: 'string' },
|
|
45
|
-
evidence: { type: 'string' },
|
|
46
|
-
},
|
|
47
|
-
output: {
|
|
48
|
-
schema: {
|
|
49
|
-
type: 'object', additionalProperties: true,
|
|
50
|
-
properties: {
|
|
51
|
-
ok: { type: 'boolean', required: true },
|
|
52
|
-
phase: { type: 'string' },
|
|
53
|
-
error: { type: 'string' },
|
|
54
|
-
verify: { type: 'object', additionalProperties: true },
|
|
55
|
-
}
|
|
56
|
-
},
|
|
57
|
-
render: (_a, v) => [{ type: 'text', text: v.ok ? 'ok' : (v.error ?? 'error') }],
|
|
58
|
-
},
|
|
59
|
-
async execute(args, exec) {
|
|
60
|
-
const op = args.op;
|
|
61
|
-
const rawTest = args.testFile;
|
|
62
|
-
const root = workspaceRootFor(configuredRoot, exec);
|
|
63
|
-
if (rawTest && !(await isInsideRoot(root, rawTest)))
|
|
64
|
-
return { text: `Path "${rawTest}" escapes the workspace root.`, truncated: false };
|
|
65
|
-
if (op === 'red') {
|
|
66
|
-
if (!rawTest)
|
|
67
|
-
return { text: 'testFile required for red', truncated: false };
|
|
68
|
-
const abs = resolve(root, rawTest);
|
|
69
|
-
try {
|
|
70
|
-
const s = await stat(abs);
|
|
71
|
-
if (!s.isFile())
|
|
72
|
-
return { ok: false, phase: 'red', error: 'test file not found' };
|
|
73
|
-
}
|
|
74
|
-
catch {
|
|
75
|
-
return { ok: false, phase: 'red', error: 'test file not found' };
|
|
76
|
-
}
|
|
77
|
-
const content = await readFile(abs, 'utf-8').catch(() => '');
|
|
78
|
-
// red evidence is that file contains failing expectation (throw, expect fail, etc.)
|
|
79
|
-
redEvidence.add(rawTest);
|
|
80
|
-
return { ok: true, phase: 'red', testFile: rawTest, evidence: content.slice(0, 500), redEvidenceSize: redEvidence.size };
|
|
81
|
-
}
|
|
82
|
-
if (op === 'green') {
|
|
83
|
-
if (!rawTest)
|
|
84
|
-
return { text: 'testFile required for green', truncated: false };
|
|
85
|
-
if (!redEvidence.has(rawTest)) {
|
|
86
|
-
// also check file exists? If not in redEvidence, error must contain 'red'
|
|
87
|
-
return { ok: false, phase: 'green', error: 'red evidence required before green — run op:red first' };
|
|
88
|
-
}
|
|
89
|
-
const abs = resolve(root, rawTest);
|
|
90
|
-
try {
|
|
91
|
-
await stat(abs);
|
|
92
|
-
}
|
|
93
|
-
catch {
|
|
94
|
-
return { ok: false, phase: 'green', error: 'test file not found' };
|
|
95
|
-
}
|
|
96
|
-
return { ok: true, phase: 'green', testFile: rawTest };
|
|
97
|
-
}
|
|
98
|
-
if (op === 'verify') {
|
|
99
|
-
// try to run pnpm verify -- if not available, return ok false but with verify object
|
|
100
|
-
try {
|
|
101
|
-
const { stdout } = await execFileAsync('pnpm', ['verify'], { cwd: root, timeout: 30000 });
|
|
102
|
-
return { ok: true, phase: 'verify', verify: { passed: true, output: String(stdout).slice(0, 2000) } };
|
|
103
|
-
}
|
|
104
|
-
catch (e) {
|
|
105
|
-
const out = (e.stdout ?? '') + (e.stderr ?? '') + String(e.message);
|
|
106
|
-
const passed = out.includes('Tests') && !out.includes('FAIL');
|
|
107
|
-
return { ok: passed, phase: 'verify', verify: { passed, output: out.slice(0, 2000) }, error: passed ? undefined : 'verify failed' };
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
return { text: `unknown op ${op}`, truncated: false };
|
|
111
|
-
}
|
|
112
|
-
}), 'tdd evidence'));
|
|
113
|
-
}
|
|
114
|
-
//# sourceMappingURL=tdd-evidence-tool.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"tdd-evidence-tool.js","sourceRoot":"","sources":["../src/host/tdd-evidence-tool.ts"],"names":[],"mappings":"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"}
|
package/lib/webhook-secret.d.ts
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Webhook secret generation and the URL an operator pastes into GitLab.
|
|
3
|
-
*
|
|
4
|
-
* Parked at the meta root when the Maestro settings card lost its GitLab tab,
|
|
5
|
-
* and never ported: `review` kept the secret FIELD in its own settings section
|
|
6
|
-
* but had no way to produce a value for it, so the operator had to invent a
|
|
7
|
-
* 32-character base64url string by hand. A pasted secret with a `+`, a `/` or
|
|
8
|
-
* a `=` is a common outcome, and those characters are exactly what GitLab's
|
|
9
|
-
* token comparison and a URL path segment cannot carry.
|
|
10
|
-
*/
|
|
11
|
-
/** The merge-request webhook path this plugin serves. */
|
|
12
|
-
export declare const GITLAB_WEBHOOK_PATH = "/hooks/gitlab-mr";
|
|
13
|
-
/**
|
|
14
|
-
* Generate an opaque 256-bit secret suitable for GitLab's webhook token.
|
|
15
|
-
*
|
|
16
|
-
* Each byte contributes 6 bits (`byte & 0b00111111`), so the result is always
|
|
17
|
-
* 32 base64url characters with no padding and no character outside the
|
|
18
|
-
* alphabet — the two properties GitLab's comparison and a URL path segment
|
|
19
|
-
* both need. The randomness source is injectable so the mapping is testable
|
|
20
|
-
* without weakening the production path.
|
|
21
|
-
*/
|
|
22
|
-
export declare function generateWebhookSecret(randomValues?: (array: Uint8Array) => Uint8Array): string;
|
|
23
|
-
/**
|
|
24
|
-
* GitLab's merge-request webhook endpoint for the configured public hostname.
|
|
25
|
-
*
|
|
26
|
-
* A user pasting the value back out of the settings field usually brings a
|
|
27
|
-
* scheme and a trailing slash with it, so both are stripped. An absent
|
|
28
|
-
* hostname names itself rather than producing a URL that looks real.
|
|
29
|
-
*/
|
|
30
|
-
export declare function gitlabWebhookUrl(hostname?: string): string;
|
|
31
|
-
//# sourceMappingURL=webhook-secret.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"webhook-secret.d.ts","sourceRoot":"","sources":["../src/host/webhook-secret.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,yDAAyD;AACzD,eAAO,MAAM,mBAAmB,qBAAqB,CAAA;AAErD;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CACnC,YAAY,GAAE,CAAC,KAAK,EAAE,UAAU,KAAK,UAAsE,GAC1G,MAAM,CAGR;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAG1D"}
|
package/lib/webhook-secret.js
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Webhook secret generation and the URL an operator pastes into GitLab.
|
|
3
|
-
*
|
|
4
|
-
* Parked at the meta root when the Maestro settings card lost its GitLab tab,
|
|
5
|
-
* and never ported: `review` kept the secret FIELD in its own settings section
|
|
6
|
-
* but had no way to produce a value for it, so the operator had to invent a
|
|
7
|
-
* 32-character base64url string by hand. A pasted secret with a `+`, a `/` or
|
|
8
|
-
* a `=` is a common outcome, and those characters are exactly what GitLab's
|
|
9
|
-
* token comparison and a URL path segment cannot carry.
|
|
10
|
-
*/
|
|
11
|
-
const BASE64URL_ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';
|
|
12
|
-
/** The merge-request webhook path this plugin serves. */
|
|
13
|
-
export const GITLAB_WEBHOOK_PATH = '/hooks/gitlab-mr';
|
|
14
|
-
/**
|
|
15
|
-
* Generate an opaque 256-bit secret suitable for GitLab's webhook token.
|
|
16
|
-
*
|
|
17
|
-
* Each byte contributes 6 bits (`byte & 0b00111111`), so the result is always
|
|
18
|
-
* 32 base64url characters with no padding and no character outside the
|
|
19
|
-
* alphabet — the two properties GitLab's comparison and a URL path segment
|
|
20
|
-
* both need. The randomness source is injectable so the mapping is testable
|
|
21
|
-
* without weakening the production path.
|
|
22
|
-
*/
|
|
23
|
-
export function generateWebhookSecret(randomValues = globalThis.crypto.getRandomValues.bind(globalThis.crypto)) {
|
|
24
|
-
const bytes = randomValues(new Uint8Array(32));
|
|
25
|
-
return Array.from(bytes, byte => BASE64URL_ALPHABET[byte & 0b00111111]).join('');
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* GitLab's merge-request webhook endpoint for the configured public hostname.
|
|
29
|
-
*
|
|
30
|
-
* A user pasting the value back out of the settings field usually brings a
|
|
31
|
-
* scheme and a trailing slash with it, so both are stripped. An absent
|
|
32
|
-
* hostname names itself rather than producing a URL that looks real.
|
|
33
|
-
*/
|
|
34
|
-
export function gitlabWebhookUrl(hostname) {
|
|
35
|
-
const authority = hostname?.trim().replace(/^https?:\/\//, '').replace(/\/+$/, '') || '<your-hostname>';
|
|
36
|
-
return `https://${authority}${GITLAB_WEBHOOK_PATH}`;
|
|
37
|
-
}
|
|
38
|
-
//# sourceMappingURL=webhook-secret.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"webhook-secret.js","sourceRoot":"","sources":["../src/host/webhook-secret.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,MAAM,kBAAkB,GAAG,kEAAkE,CAAA;AAE7F,yDAAyD;AACzD,MAAM,CAAC,MAAM,mBAAmB,GAAG,kBAAkB,CAAA;AAErD;;;;;;;;GAQG;AACH,MAAM,UAAU,qBAAqB,CACnC,eAAkD,UAAU,CAAC,MAAM,CAAC,eAAe,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC;IAE3G,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC,CAAA;IAC9C,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,CAAC,kBAAkB,CAAC,IAAI,GAAG,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;AAClF,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAC,QAAiB;IAChD,MAAM,SAAS,GAAG,QAAQ,EAAE,IAAI,EAAE,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,iBAAiB,CAAA;IACvG,OAAO,WAAW,SAAS,GAAG,mBAAmB,EAAE,CAAA;AACrD,CAAC"}
|
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
import { join, resolve, sep, basename } from 'node:path'
|
|
2
|
-
import { stat, realpath } from 'node:fs/promises'
|
|
3
|
-
import { execFile } from 'node:child_process'
|
|
4
|
-
import { promisify } from 'node:util'
|
|
5
|
-
import type { Context } from '@deepseek-ai/cordis'
|
|
6
|
-
import { defineTool } from '@deepseek-ai/dsh-tools'
|
|
7
|
-
import z from '@deepseek-ai/schemastery'
|
|
8
|
-
|
|
9
|
-
export const name='maestro-git-worktree-tool'
|
|
10
|
-
export const inject=['tools']
|
|
11
|
-
export const Config:z<{rootPath?:string}> = z.object({rootPath:z.string()})
|
|
12
|
-
interface SC{agent?:{session?:{header?:{cwd?:string}}}}
|
|
13
|
-
function workspaceRootFor(c:string|undefined,e:unknown):string{ if(c!==undefined) return c; const cwd=(e as SC|undefined)?.agent?.session?.header?.cwd; return typeof cwd==='string'&&cwd!==''?cwd:process.cwd()}
|
|
14
|
-
async function isInsideRoot(r:string,t:string):Promise<boolean>{
|
|
15
|
-
const ar=resolve(r); const rs=resolve(ar,t)
|
|
16
|
-
if(rs!==ar && !rs.startsWith(ar+sep)) return false
|
|
17
|
-
// For non-existent targets (create), realpath fails — allow if string prefix passes and parent is inside
|
|
18
|
-
try{ const rr=await realpath(ar); const rt=await realpath(rs); return rt===rr||rt.startsWith(rr+sep)}catch{
|
|
19
|
-
try{ const rr=await realpath(ar); const parent=resolve(rs,'..'); const rp=await realpath(parent); return rp===rr||rp.startsWith(rr+sep) }catch{ return rs===ar || rs.startsWith(ar+sep) }
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
const SAFE_BRANCH=/^[A-Za-z0-9._\/-]+$/
|
|
23
|
-
const execFileAsync=promisify(execFile)
|
|
24
|
-
async function runGit(cwd:string, args:string[]):Promise<{code:number|null, stdout:string, stderr:string}>{
|
|
25
|
-
try{
|
|
26
|
-
const {stdout, stderr}=await execFileAsync('git', args, {cwd, timeout:10000}) as any
|
|
27
|
-
return {code:0, stdout: String(stdout), stderr: String(stderr)}
|
|
28
|
-
}catch(e:any){
|
|
29
|
-
return {code:e.code ?? 1, stdout: e.stdout ?? '', stderr: e.stderr ?? String(e.message)}
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
async function exists(p:string):Promise<boolean>{ try{await stat(p); return true}catch{return false}}
|
|
33
|
-
|
|
34
|
-
export function apply(ctx:Context, config:{rootPath?:string}={}):void{
|
|
35
|
-
const configuredRoot=config.rootPath
|
|
36
|
-
ctx.effect(()=>ctx.tools.register(defineTool({
|
|
37
|
-
name:'git_worktree',
|
|
38
|
-
description:'Inspect/create/remove git worktrees deterministically (isolated workspace, branch, submodule guard).',
|
|
39
|
-
parameters:{
|
|
40
|
-
op:{type:'string', enum:['inspect','create','remove'], required:true},
|
|
41
|
-
worktreePath:{type:'string', required:true},
|
|
42
|
-
branch:{type:'string'},
|
|
43
|
-
base:{type:'string'},
|
|
44
|
-
},
|
|
45
|
-
output:{
|
|
46
|
-
schema:{
|
|
47
|
-
type:'object', additionalProperties:true,
|
|
48
|
-
properties:{
|
|
49
|
-
op:{type:'string', required:true},
|
|
50
|
-
exists:{type:'boolean'},
|
|
51
|
-
isWorktree:{type:'boolean'},
|
|
52
|
-
created:{type:'boolean'},
|
|
53
|
-
reason:{type:'string'},
|
|
54
|
-
}
|
|
55
|
-
},
|
|
56
|
-
render:(_a,v)=>[{type:'text', text: JSON.stringify(v,null,2)}],
|
|
57
|
-
},
|
|
58
|
-
async execute(args, exec){
|
|
59
|
-
const op=(args as {op:string}).op
|
|
60
|
-
const rawPath=(args as {worktreePath:string}).worktreePath
|
|
61
|
-
const root=workspaceRootFor(configuredRoot, exec)
|
|
62
|
-
if(!(await isInsideRoot(root, rawPath))) return {text:`Path "${rawPath}" escapes the workspace root.`, truncated:false} as never
|
|
63
|
-
const worktreePath=resolve(root, rawPath)
|
|
64
|
-
|
|
65
|
-
if(op==='inspect'){
|
|
66
|
-
const ex=await exists(worktreePath)
|
|
67
|
-
let isWorktree=false, branch:string|null=null, headSha:string|null=null, isClean=true, gitDir:string|null=null, gitCommonDir:string|null=null
|
|
68
|
-
if(ex){
|
|
69
|
-
// try git rev-parse
|
|
70
|
-
const r1=await runGit(worktreePath, ['rev-parse','--git-dir'])
|
|
71
|
-
const r2=await runGit(worktreePath, ['rev-parse','--git-common-dir'])
|
|
72
|
-
const r3=await runGit(worktreePath, ['branch','--show-current'])
|
|
73
|
-
const r4=await runGit(worktreePath, ['rev-parse','HEAD'])
|
|
74
|
-
const r5=await runGit(worktreePath, ['status','--porcelain'])
|
|
75
|
-
if(r1.code===0) gitDir=r1.stdout.trim()
|
|
76
|
-
if(r2.code===0) gitCommonDir=r2.stdout.trim()
|
|
77
|
-
if(r3.code===0) branch=r3.stdout.trim()||null
|
|
78
|
-
if(r4.code===0) headSha=r4.stdout.trim()||null
|
|
79
|
-
isClean=r5.stdout.trim()===''
|
|
80
|
-
// isWorktree if gitDir is file and gitCommonDir differs
|
|
81
|
-
if(gitDir && gitCommonDir && gitDir!==gitCommonDir) isWorktree=true
|
|
82
|
-
// fallback: if worktreePath contains .worktrees
|
|
83
|
-
if(worktreePath.includes('/.worktrees/')) isWorktree=true
|
|
84
|
-
}
|
|
85
|
-
return {op:'inspect', exists:ex, branch, headSha, isClean, isWorktree, gitDir, gitCommonDir, untrackedFiles:[], truncated:false, ignored:null} as never
|
|
86
|
-
}
|
|
87
|
-
if(op==='create'){
|
|
88
|
-
const branch=(args as {branch?:string}).branch
|
|
89
|
-
const base=(args as {base?:string}).base ?? 'HEAD'
|
|
90
|
-
if(!branch) return {text:'branch required for create', truncated:false} as never
|
|
91
|
-
if(!SAFE_BRANCH.test(branch) || branch.startsWith('-') || branch.includes('..')) return {text:`invalid branch name "${branch}" — must match ${SAFE_BRANCH.source}`, truncated:false} as never
|
|
92
|
-
if(branch.includes('--')) return {text:`invalid branch name "${branch}"`, truncated:false} as never
|
|
93
|
-
// base validate
|
|
94
|
-
if(base && !SAFE_BRANCH.test(base) && !/^[0-9a-f]{7,40}$/.test(base)) return {text:`invalid base "${base}"`, truncated:false} as never
|
|
95
|
-
// .gitignore guard: check if worktreePath is ignored
|
|
96
|
-
const check=await runGit(root, ['check-ignore','-q', worktreePath])
|
|
97
|
-
const isIgnored=check.code===0
|
|
98
|
-
if(!isIgnored){
|
|
99
|
-
return {op:'create', created:false, worktreePath, branch, headSha:'', alreadyExisted:false, reason:'not ignored — add .worktrees to .gitignore'} as never
|
|
100
|
-
}
|
|
101
|
-
if(await exists(worktreePath)){
|
|
102
|
-
return {op:'create', created:false, worktreePath, branch, headSha:'', alreadyExisted:true, reason:'already exists'} as never
|
|
103
|
-
}
|
|
104
|
-
const res=await runGit(root, ['worktree','add','-b', branch,'--', worktreePath, base])
|
|
105
|
-
if(res.code!==0){
|
|
106
|
-
if(res.stderr.includes('permission denied') || res.stderr.includes('EACCES')){
|
|
107
|
-
return {op:'create', created:false, worktreePath, branch, headSha:'', alreadyExisted:false, reason:'blocked by sandbox — working in place'} as never
|
|
108
|
-
}
|
|
109
|
-
return {op:'create', created:false, worktreePath, branch, headSha:'', alreadyExisted:false, reason: res.stderr.slice(0,500)} as never
|
|
110
|
-
}
|
|
111
|
-
const head=await runGit(worktreePath, ['rev-parse','HEAD'])
|
|
112
|
-
return {op:'create', created:true, worktreePath, branch, headSha: head.stdout.trim(), alreadyExisted:false, reason:null} as never
|
|
113
|
-
}
|
|
114
|
-
if(op==='remove'){
|
|
115
|
-
const ex=await exists(worktreePath)
|
|
116
|
-
if(!ex) return {op:'remove', removed:false, pruned:false, reason:'not exists', dirtyFiles:[]} as never
|
|
117
|
-
const status=await runGit(worktreePath, ['status','--porcelain'])
|
|
118
|
-
const dirtyFiles=status.stdout.trim()? status.stdout.trim().split('\n').slice(0,20):[]
|
|
119
|
-
if(dirtyFiles.length>0){
|
|
120
|
-
return {op:'remove', removed:false, pruned:false, reason:'contains modified or untracked files', dirtyFiles} as never
|
|
121
|
-
}
|
|
122
|
-
const res=await runGit(root, ['worktree','remove','--', worktreePath])
|
|
123
|
-
if(res.code!==0) return {op:'remove', removed:false, pruned:false, reason: res.stderr.slice(0,500), dirtyFiles} as never
|
|
124
|
-
const prune=await runGit(root, ['worktree','prune'])
|
|
125
|
-
return {op:'remove', removed:true, pruned: prune.code===0, reason:null, dirtyFiles:[]} as never
|
|
126
|
-
}
|
|
127
|
-
return {text:`unknown op ${op}`, truncated:false} as never
|
|
128
|
-
}
|
|
129
|
-
}), 'git worktree'))
|
|
130
|
-
}
|