opencode-gitlab-dap 1.8.3 → 1.9.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/dist/index.cjs +70 -103
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +71 -104
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -2259,7 +2259,30 @@ This project may have persistent memory and skills available via knowledge tools
|
|
|
2259
2259
|
Use gitlab_memory_load to check for existing project context (facts, decisions, patterns).
|
|
2260
2260
|
Use gitlab_skill_list to discover available task-specific skills.
|
|
2261
2261
|
When you learn something new about the project, use gitlab_memory_record to preserve it.
|
|
2262
|
-
When you complete a significant task, consider using gitlab_memory_log_session to log learnings
|
|
2262
|
+
When you complete a significant task, consider using gitlab_memory_log_session to log learnings.
|
|
2263
|
+
|
|
2264
|
+
### Bootstrap Project Memory
|
|
2265
|
+
When the user says "bootstrap project memory", "initialize memory", or "build project knowledge":
|
|
2266
|
+
1. FIRST: Determine the project path by running \`run_git_command("remote", ["-v"])\` and extracting the path from the git remote URL (e.g., "git@gitlab.com:my-group/my-project.git" \u2192 "my-group/my-project"). NEVER guess the project path.
|
|
2267
|
+
2. Call gitlab_memory_load with the extracted project path to check if memory already exists.
|
|
2268
|
+
3. If memory exists, show a summary and ask if the user wants to refresh it.
|
|
2269
|
+
4. If memory is empty (or user wants refresh), gather project knowledge by:
|
|
2270
|
+
a. Read the project README, key config files, and codebase structure (use file/repo tools).
|
|
2271
|
+
b. Fetch project details via gitlab_get_project.
|
|
2272
|
+
c. List open issues (gitlab_list_issues, state=opened, limit=20).
|
|
2273
|
+
d. List open merge requests (gitlab_list_merge_requests, state=opened, limit=10).
|
|
2274
|
+
e. Check recent pipelines (gitlab_list_pipelines, limit=5).
|
|
2275
|
+
f. List project members (gitlab_list_project_members).
|
|
2276
|
+
5. Record each category as separate memory entries using gitlab_memory_record:
|
|
2277
|
+
- fact: project overview (name, purpose, tech stack, language, dependencies)
|
|
2278
|
+
- fact: architecture and codebase structure (key files, modules, patterns)
|
|
2279
|
+
- fact: CI/CD pipeline configuration (stages, jobs, deployment targets)
|
|
2280
|
+
- fact: open issues summary (count, key issues, labels)
|
|
2281
|
+
- fact: open MRs summary (count, key MRs, review status)
|
|
2282
|
+
- fact: team and contributors
|
|
2283
|
+
- pattern: development workflow observations (branching, review process, release cycle)
|
|
2284
|
+
6. Log a session with gitlab_memory_log_session summarizing the bootstrap.
|
|
2285
|
+
IMPORTANT: Always extract the project path from git remote \u2014 never guess it. Fire multiple gitlab_memory_record calls in parallel \u2014 each creates its own page, so parallel writes are safe.`;
|
|
2263
2286
|
|
|
2264
2287
|
// src/hooks.ts
|
|
2265
2288
|
function buildFlowSubagentPrompt(flow, projectPath, projectUrl) {
|
|
@@ -3612,13 +3635,13 @@ async function searchWikiPages(instanceUrl, token, scope, id, query) {
|
|
|
3612
3635
|
// src/tools/memory-tools.ts
|
|
3613
3636
|
var z5 = import_plugin5.tool.schema;
|
|
3614
3637
|
var PREFIX = "agents";
|
|
3615
|
-
var
|
|
3638
|
+
var MEMORY_DIRS = {
|
|
3616
3639
|
all: [`${PREFIX}/memory/facts`, `${PREFIX}/memory/decisions`, `${PREFIX}/memory/patterns`],
|
|
3617
3640
|
facts: [`${PREFIX}/memory/facts`],
|
|
3618
3641
|
decisions: [`${PREFIX}/memory/decisions`],
|
|
3619
3642
|
patterns: [`${PREFIX}/memory/patterns`]
|
|
3620
3643
|
};
|
|
3621
|
-
var
|
|
3644
|
+
var RECORD_DIR = {
|
|
3622
3645
|
fact: `${PREFIX}/memory/facts`,
|
|
3623
3646
|
decision: `${PREFIX}/memory/decisions`,
|
|
3624
3647
|
pattern: `${PREFIX}/memory/patterns`
|
|
@@ -3629,52 +3652,9 @@ function today() {
|
|
|
3629
3652
|
function slugify(text) {
|
|
3630
3653
|
return text.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "").slice(0, 60);
|
|
3631
3654
|
}
|
|
3632
|
-
|
|
3633
|
-
|
|
3634
|
-
|
|
3635
|
-
return page.content;
|
|
3636
|
-
} catch {
|
|
3637
|
-
return null;
|
|
3638
|
-
}
|
|
3639
|
-
}
|
|
3640
|
-
var MAX_RETRIES = 3;
|
|
3641
|
-
var RETRY_DELAY_MS = 1e3;
|
|
3642
|
-
async function sleep2(ms) {
|
|
3643
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
3644
|
-
}
|
|
3645
|
-
async function appendToPage(instanceUrl, token, scope, id, slug, newContent) {
|
|
3646
|
-
for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {
|
|
3647
|
-
const existing2 = await safeRead(instanceUrl, token, scope, id, slug);
|
|
3648
|
-
if (existing2 !== null) {
|
|
3649
|
-
try {
|
|
3650
|
-
await updateWikiPage(instanceUrl, token, scope, id, slug, existing2 + "\n\n" + newContent);
|
|
3651
|
-
return;
|
|
3652
|
-
} catch (err) {
|
|
3653
|
-
if (attempt < MAX_RETRIES - 1 && err.message?.includes("reference update")) {
|
|
3654
|
-
await sleep2(RETRY_DELAY_MS * (attempt + 1));
|
|
3655
|
-
continue;
|
|
3656
|
-
}
|
|
3657
|
-
throw err;
|
|
3658
|
-
}
|
|
3659
|
-
} else {
|
|
3660
|
-
try {
|
|
3661
|
-
await createWikiPage(instanceUrl, token, scope, id, slug, newContent);
|
|
3662
|
-
return;
|
|
3663
|
-
} catch (err) {
|
|
3664
|
-
if (err.message?.includes("Duplicate page") || err.message?.includes("reference update")) {
|
|
3665
|
-
await sleep2(RETRY_DELAY_MS * (attempt + 1));
|
|
3666
|
-
continue;
|
|
3667
|
-
}
|
|
3668
|
-
throw err;
|
|
3669
|
-
}
|
|
3670
|
-
}
|
|
3671
|
-
}
|
|
3672
|
-
const existing = await safeRead(instanceUrl, token, scope, id, slug);
|
|
3673
|
-
if (existing !== null) {
|
|
3674
|
-
await updateWikiPage(instanceUrl, token, scope, id, slug, existing + "\n\n" + newContent);
|
|
3675
|
-
} else {
|
|
3676
|
-
throw new Error(`Failed to append to ${slug} after ${MAX_RETRIES} retries`);
|
|
3677
|
-
}
|
|
3655
|
+
function titleFromContent(content) {
|
|
3656
|
+
const first = content.split("\n")[0].replace(/^[#*\->\s]+/, "").trim();
|
|
3657
|
+
return first.slice(0, 80) || "untitled";
|
|
3678
3658
|
}
|
|
3679
3659
|
function validateProjectId(projectId) {
|
|
3680
3660
|
if (!projectId.includes("/")) {
|
|
@@ -3711,25 +3691,38 @@ function makeMemoryTools(ctx) {
|
|
|
3711
3691
|
const auth = authAndValidate(args.project_id);
|
|
3712
3692
|
const { scope, id } = resolveScope(args);
|
|
3713
3693
|
const memType = args.type ?? "all";
|
|
3714
|
-
const
|
|
3715
|
-
if (!
|
|
3716
|
-
|
|
3717
|
-
|
|
3718
|
-
|
|
3719
|
-
|
|
3720
|
-
|
|
3721
|
-
|
|
3694
|
+
const dirs = MEMORY_DIRS[memType];
|
|
3695
|
+
if (!dirs) return `Unknown memory type: ${memType}`;
|
|
3696
|
+
try {
|
|
3697
|
+
const allPages = await listWikiPages(
|
|
3698
|
+
auth.instanceUrl,
|
|
3699
|
+
auth.token,
|
|
3700
|
+
scope,
|
|
3701
|
+
id,
|
|
3702
|
+
true
|
|
3703
|
+
);
|
|
3704
|
+
const sections = [];
|
|
3705
|
+
for (const dir of dirs) {
|
|
3706
|
+
const label = dir.split("/").pop();
|
|
3707
|
+
const pages = allPages.filter((p) => p.slug.startsWith(dir + "/") && p.content);
|
|
3708
|
+
if (pages.length === 0) continue;
|
|
3709
|
+
const entries = pages.map((p) => p.content).join("\n\n---\n\n");
|
|
3710
|
+
sections.push(
|
|
3711
|
+
`## ${label.charAt(0).toUpperCase() + label.slice(1)} (${pages.length})
|
|
3722
3712
|
|
|
3723
|
-
${
|
|
3713
|
+
${entries}`
|
|
3714
|
+
);
|
|
3724
3715
|
}
|
|
3716
|
+
if (sections.length === 0)
|
|
3717
|
+
return "No project memory found. Use gitlab_memory_record to start building project knowledge.";
|
|
3718
|
+
return sections.join("\n\n---\n\n");
|
|
3719
|
+
} catch (err) {
|
|
3720
|
+
return `Error loading memory: ${err.message}`;
|
|
3725
3721
|
}
|
|
3726
|
-
if (sections.length === 0)
|
|
3727
|
-
return "No project memory found. Use gitlab_memory_record to start building project knowledge.";
|
|
3728
|
-
return sections.join("\n\n---\n\n");
|
|
3729
3722
|
}
|
|
3730
3723
|
}),
|
|
3731
3724
|
gitlab_memory_record: (0, import_plugin5.tool)({
|
|
3732
|
-
description: "Record a fact, decision, or pattern in project memory.\nFacts: stable truths about the project (e.g., deploy targets, tech stack, team conventions).\nDecisions: architectural choices with reasoning (why X was chosen over Y).\nPatterns: recurring observations that may evolve into skills over time.\
|
|
3725
|
+
description: "Record a fact, decision, or pattern in project memory.\nFacts: stable truths about the project (e.g., deploy targets, tech stack, team conventions).\nDecisions: architectural choices with reasoning (why X was chosen over Y).\nPatterns: recurring observations that may evolve into skills over time.\nEach record creates its own page \u2014 safe for parallel writes.",
|
|
3733
3726
|
args: {
|
|
3734
3727
|
project_id: z5.string().describe(
|
|
3735
3728
|
'FULL project path with namespace (e.g., "gitlab-org/gitlab"). Must contain a slash. Never use just the project name.'
|
|
@@ -3742,24 +3735,18 @@ ${content}`);
|
|
|
3742
3735
|
execute: async (args) => {
|
|
3743
3736
|
const auth = authAndValidate(args.project_id);
|
|
3744
3737
|
const { scope, id } = resolveScope(args);
|
|
3745
|
-
const
|
|
3746
|
-
if (!
|
|
3738
|
+
const dir = RECORD_DIR[args.type];
|
|
3739
|
+
if (!dir) return `Unknown memory type: ${args.type}`;
|
|
3747
3740
|
const date = today();
|
|
3748
|
-
|
|
3749
|
-
|
|
3750
|
-
|
|
3751
|
-
|
|
3752
|
-
|
|
3753
|
-
|
|
3754
|
-
formatted = `## ${date}
|
|
3755
|
-
- ${args.content.replace(/\n/g, "\n- ")}`;
|
|
3756
|
-
} else {
|
|
3757
|
-
formatted = `## ${date}
|
|
3758
|
-
${args.content}`;
|
|
3759
|
-
}
|
|
3741
|
+
const title = titleFromContent(args.content);
|
|
3742
|
+
const slug = `${dir}/${date}-${slugify(title)}`;
|
|
3743
|
+
const header = `*Recorded: ${date} | Type: ${args.type}*
|
|
3744
|
+
|
|
3745
|
+
`;
|
|
3746
|
+
const body = header + args.content;
|
|
3760
3747
|
try {
|
|
3761
|
-
await
|
|
3762
|
-
return `Recorded ${args.type} in project memory
|
|
3748
|
+
await createWikiPage(auth.instanceUrl, auth.token, scope, id, slug, body);
|
|
3749
|
+
return `Recorded ${args.type} in project memory: ${slug}`;
|
|
3763
3750
|
} catch (err) {
|
|
3764
3751
|
return `Error recording ${args.type}: ${err.message}`;
|
|
3765
3752
|
}
|
|
@@ -3815,32 +3802,12 @@ ${args.content}`;
|
|
|
3815
3802
|
const { scope, id } = resolveScope(args);
|
|
3816
3803
|
const date = today();
|
|
3817
3804
|
const slug = `${PREFIX}/memory/sessions/${date}-${slugify(args.title)}`;
|
|
3818
|
-
|
|
3819
|
-
|
|
3820
|
-
|
|
3821
|
-
|
|
3822
|
-
|
|
3823
|
-
const msg = err.message ?? "";
|
|
3824
|
-
if (msg.includes("Duplicate page") || msg.includes("already exists") || msg.includes("422")) {
|
|
3825
|
-
try {
|
|
3826
|
-
await updateWikiPage(auth.instanceUrl, auth.token, scope, id, slug, args.summary);
|
|
3827
|
-
return `Session log updated: ${slug}`;
|
|
3828
|
-
} catch (err2) {
|
|
3829
|
-
if (attempt < MAX_RETRIES - 1 && err2.message?.includes("reference update")) {
|
|
3830
|
-
await sleep2(RETRY_DELAY_MS * (attempt + 1));
|
|
3831
|
-
continue;
|
|
3832
|
-
}
|
|
3833
|
-
return `Error logging session: ${err2.message}`;
|
|
3834
|
-
}
|
|
3835
|
-
}
|
|
3836
|
-
if (attempt < MAX_RETRIES - 1 && msg.includes("reference update")) {
|
|
3837
|
-
await sleep2(RETRY_DELAY_MS * (attempt + 1));
|
|
3838
|
-
continue;
|
|
3839
|
-
}
|
|
3840
|
-
return `Error logging session: ${msg}`;
|
|
3841
|
-
}
|
|
3805
|
+
try {
|
|
3806
|
+
await createWikiPage(auth.instanceUrl, auth.token, scope, id, slug, args.summary);
|
|
3807
|
+
return `Session logged: ${slug}`;
|
|
3808
|
+
} catch (err) {
|
|
3809
|
+
return `Error logging session: ${err.message}`;
|
|
3842
3810
|
}
|
|
3843
|
-
return `Error logging session: failed after ${MAX_RETRIES} retries`;
|
|
3844
3811
|
}
|
|
3845
3812
|
})
|
|
3846
3813
|
};
|