glab-agent 0.2.2 → 0.2.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "glab-agent",
3
- "version": "0.2.2",
3
+ "version": "0.2.4",
4
4
  "type": "module",
5
5
  "description": "Multi-agent GitLab To-Do watcher with YAML-defined agents, skills, and GitLab registry.",
6
6
  "license": "MIT",
@@ -797,6 +797,76 @@ async function updateAgentUserBio(
797
797
  }
798
798
  }
799
799
 
800
+ async function publishAgentProfileWiki(
801
+ config: LocalAgentConfig,
802
+ dependencies: WatcherDependencies
803
+ ): Promise<void> {
804
+ const logger = dependencies.logger ?? console;
805
+ const def = config.agentDefinition;
806
+ if (!def || !config.gitlabProjectId) return;
807
+
808
+ const agentName = def.name;
809
+ const slug = `agents/${agentName}`;
810
+
811
+ // Build profile page content
812
+ const lines: string[] = [
813
+ `# ${def.display_name || agentName}`,
814
+ "",
815
+ ];
816
+
817
+ if (def.description) {
818
+ lines.push(def.description, "");
819
+ }
820
+
821
+ // Skills section — skill_refs are the string names from YAML; fall back to parsed skill objects
822
+ const skillNames = def.skill_refs.length > 0
823
+ ? def.skill_refs
824
+ : def.skills.map(s => s.name);
825
+ if (skillNames.length > 0) {
826
+ lines.push("## Skills", "", ...skillNames.map(s => `- ${s}`), "");
827
+ }
828
+
829
+ // Triggers section
830
+ const triggers = def.triggers;
831
+ if (triggers.labels.length > 0) {
832
+ lines.push("## Trigger Labels", "", ...triggers.labels.map(l => `- \`${l}\``), "");
833
+ }
834
+
835
+ // Instructions preview (from preamble)
836
+ if (def.prompt.preamble) {
837
+ lines.push("## Instructions", "", def.prompt.preamble.trim(), "");
838
+ }
839
+
840
+ // How to use section
841
+ const botMention = config.botUsername ? `@${config.botUsername}` : `@${agentName}`;
842
+ lines.push(
843
+ "## How to Use",
844
+ "",
845
+ `在 GitLab issue 或 MR 中评论 \`${botMention} <你的需求>\`,agent 会自动接单处理。`,
846
+ "",
847
+ "## Status",
848
+ "",
849
+ `> Provider: \`${def.provider}\` | Poll interval: ${def.poll_interval_seconds ?? 30}s`,
850
+ `>`,
851
+ `> *Auto-updated by glab-agent on ${new Date().toISOString().slice(0, 16).replace("T", " ")}*`,
852
+ );
853
+
854
+ const content = lines.join("\n");
855
+
856
+ try {
857
+ const pages = await dependencies.gitlabClient.listWikiPages(config.gitlabProjectId);
858
+ const existing = pages.find(p => p.slug === slug || p.slug === `agents-${agentName}`);
859
+ if (existing) {
860
+ await dependencies.gitlabClient.updateWikiPage(config.gitlabProjectId, existing.slug, slug, content);
861
+ } else {
862
+ await dependencies.gitlabClient.createWikiPage(config.gitlabProjectId, slug, content);
863
+ }
864
+ logger.info(`Wiki profile published: agents/${agentName}`);
865
+ } catch (error) {
866
+ logger.info?.(`Wiki profile update skipped: ${String(error).slice(0, 100)}`);
867
+ }
868
+ }
869
+
800
870
  export async function markAgentOffline(
801
871
  _config: LocalAgentConfig,
802
872
  gitlabClient: GitlabClient,
@@ -981,7 +1051,8 @@ function createDependencies(config: LocalAgentConfig, logger?: Logger): WatcherD
981
1051
  stateStore: new FileStateStore(config.statePath),
982
1052
  worktreeManager: new WorktreeManager({
983
1053
  repoPath: config.agentRepoPath,
984
- worktreeRoot: config.agentWorktreeRoot
1054
+ worktreeRoot: config.agentWorktreeRoot,
1055
+ agentName: config.agentDefinition?.name
985
1056
  }),
986
1057
  agentRunner,
987
1058
  logger
@@ -1177,6 +1248,7 @@ export async function main(argv: string[] = process.argv.slice(2)): Promise<void
1177
1248
 
1178
1249
  // Update GitLab user bio with agent profile (P1: Agent = 员工)
1179
1250
  await updateAgentUserBio(config, dependencies);
1251
+ await publishAgentProfileWiki(config, dependencies);
1180
1252
  await updateAgentUserStatus(dependencies, "idle", undefined, config);
1181
1253
  } catch (error) {
1182
1254
  logger.error(`Token validation failed for agent "${agentName}": ${String(error)}`);
@@ -13,6 +13,7 @@ export interface WorktreeInfo {
13
13
  interface WorktreeManagerOptions {
14
14
  repoPath: string;
15
15
  worktreeRoot: string;
16
+ agentName?: string;
16
17
  execFileImpl?: typeof execFileAsync;
17
18
  }
18
19
 
@@ -28,8 +29,9 @@ export function slugifyTitle(title: string): string {
28
29
  return (slug || "task").slice(0, 48);
29
30
  }
30
31
 
31
- export function branchNameForIssue(issueIid: number, title: string): string {
32
- return `agent/issue-${issueIid}-${slugifyTitle(title)}`;
32
+ export function branchNameForIssue(issueIid: number, title: string, agentName?: string): string {
33
+ const prefix = agentName ?? "agent";
34
+ return `${prefix}/issue-${issueIid}-${slugifyTitle(title)}`;
33
35
  }
34
36
 
35
37
  export function worktreePathForIssue(worktreeRoot: string, issueIid: number, title: string): string {
@@ -41,16 +43,19 @@ export class WorktreeManager {
41
43
 
42
44
  private readonly worktreeRoot: string;
43
45
 
46
+ private readonly agentName: string | undefined;
47
+
44
48
  private readonly execFileImpl: typeof execFileAsync;
45
49
 
46
50
  constructor(options: WorktreeManagerOptions) {
47
51
  this.repoPath = options.repoPath;
48
52
  this.worktreeRoot = options.worktreeRoot;
53
+ this.agentName = options.agentName;
49
54
  this.execFileImpl = options.execFileImpl ?? execFileAsync;
50
55
  }
51
56
 
52
57
  async ensureWorktree(issueIid: number, title: string): Promise<WorktreeInfo> {
53
- const branch = branchNameForIssue(issueIid, title);
58
+ const branch = branchNameForIssue(issueIid, title, this.agentName);
54
59
  const worktreePath = worktreePathForIssue(this.worktreeRoot, issueIid, title);
55
60
 
56
61
  await mkdir(this.worktreeRoot, { recursive: true });