glab-agent 0.2.5 โ 0.2.6
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
|
@@ -95,6 +95,10 @@ export interface GitlabClient {
|
|
|
95
95
|
getWikiPage(projectId: number | string, slug: string): Promise<WikiPage>;
|
|
96
96
|
createWikiPage(projectId: number | string, title: string, content: string): Promise<WikiPage>;
|
|
97
97
|
updateWikiPage(projectId: number | string, slug: string, title: string, content: string): Promise<WikiPage>;
|
|
98
|
+
getProject(projectIdOrPath: number | string): Promise<{ id: number } | undefined>;
|
|
99
|
+
createProject(name: string, options?: { visibility?: string; initializeWithReadme?: boolean }): Promise<{ id: number }>;
|
|
100
|
+
getRepositoryFile(projectId: number | string, filePath: string, ref?: string): Promise<{ content: string } | undefined>;
|
|
101
|
+
createOrUpdateRepositoryFile(projectId: number | string, filePath: string, content: string, commitMessage: string, options?: { create?: boolean }): Promise<void>;
|
|
98
102
|
}
|
|
99
103
|
|
|
100
104
|
interface GitlabGlabClientOptions {
|
|
@@ -693,6 +697,58 @@ export class GitlabGlabClient implements GitlabClient {
|
|
|
693
697
|
};
|
|
694
698
|
}
|
|
695
699
|
|
|
700
|
+
async getProject(projectIdOrPath: number | string): Promise<{ id: number } | undefined> {
|
|
701
|
+
try {
|
|
702
|
+
const encoded = typeof projectIdOrPath === "string" ? encodeURIComponent(projectIdOrPath) : projectIdOrPath;
|
|
703
|
+
const payload = await this.readJson(`projects/${encoded}`);
|
|
704
|
+
const p = (payload ?? {}) as Payload;
|
|
705
|
+
const id = Number(p.id);
|
|
706
|
+
return Number.isNaN(id) ? undefined : { id };
|
|
707
|
+
} catch {
|
|
708
|
+
return undefined;
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
async createProject(name: string, options?: { visibility?: string; initializeWithReadme?: boolean }): Promise<{ id: number }> {
|
|
713
|
+
const stdout = await this.request("projects", {
|
|
714
|
+
method: "POST",
|
|
715
|
+
fields: {
|
|
716
|
+
name,
|
|
717
|
+
path: name,
|
|
718
|
+
visibility: options?.visibility ?? "public",
|
|
719
|
+
initialize_with_readme: options?.initializeWithReadme ? "true" : "false"
|
|
720
|
+
}
|
|
721
|
+
});
|
|
722
|
+
const payload = JSON.parse(stdout) as Payload;
|
|
723
|
+
return { id: Number(payload.id) };
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
async getRepositoryFile(projectId: number | string, filePath: string, ref?: string): Promise<{ content: string } | undefined> {
|
|
727
|
+
try {
|
|
728
|
+
const encoded = typeof projectId === "string" ? encodeURIComponent(projectId) : projectId;
|
|
729
|
+
const endpoint = this.withQuery(`projects/${encoded}/repository/files/${encodeURIComponent(filePath)}`, { ref: ref ?? "main" });
|
|
730
|
+
const payload = await this.readJson(endpoint);
|
|
731
|
+
const p = (payload ?? {}) as Payload;
|
|
732
|
+
const content = typeof p.content === "string" ? Buffer.from(p.content, "base64").toString("utf8") : "";
|
|
733
|
+
return { content };
|
|
734
|
+
} catch {
|
|
735
|
+
return undefined;
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
async createOrUpdateRepositoryFile(projectId: number | string, filePath: string, content: string, commitMessage: string, options?: { create?: boolean }): Promise<void> {
|
|
740
|
+
const encoded = typeof projectId === "string" ? encodeURIComponent(projectId) : projectId;
|
|
741
|
+
const method = options?.create ? "POST" : "PUT";
|
|
742
|
+
await this.request(`projects/${encoded}/repository/files/${encodeURIComponent(filePath)}`, {
|
|
743
|
+
method,
|
|
744
|
+
fields: {
|
|
745
|
+
branch: "main",
|
|
746
|
+
content,
|
|
747
|
+
commit_message: commitMessage
|
|
748
|
+
}
|
|
749
|
+
});
|
|
750
|
+
}
|
|
751
|
+
|
|
696
752
|
/**
|
|
697
753
|
* Direct HTTP call using Node's built-in fetch.
|
|
698
754
|
* Used for endpoints where glab CLI's response parsing has issues (e.g. PUT /user/status).
|
|
@@ -882,6 +882,81 @@ async function publishAgentProfileWiki(
|
|
|
882
882
|
}
|
|
883
883
|
}
|
|
884
884
|
|
|
885
|
+
async function publishProfileReadme(
|
|
886
|
+
config: LocalAgentConfig,
|
|
887
|
+
dependencies: WatcherDependencies
|
|
888
|
+
): Promise<void> {
|
|
889
|
+
const logger = dependencies.logger ?? console;
|
|
890
|
+
const def = config.agentDefinition;
|
|
891
|
+
const username = config.botUsername;
|
|
892
|
+
if (!def || !username) return;
|
|
893
|
+
|
|
894
|
+
const projectPath = `${username}/${username}`;
|
|
895
|
+
|
|
896
|
+
// Build README content
|
|
897
|
+
const displayName = def.display_name || def.name;
|
|
898
|
+
const lines: string[] = [
|
|
899
|
+
`## ๐ Hi, I'm ${displayName}`,
|
|
900
|
+
"",
|
|
901
|
+
];
|
|
902
|
+
|
|
903
|
+
if (def.description) {
|
|
904
|
+
lines.push(def.description, "");
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
const skillNames = def.skill_refs.length > 0 ? def.skill_refs : def.skills.map(s => s.name);
|
|
908
|
+
if (skillNames.length > 0) {
|
|
909
|
+
lines.push("### ๐ Skills", "", ...skillNames.map(s => `- ${s}`), "");
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
if (def.prompt.preamble) {
|
|
913
|
+
lines.push("### ๐ What I Do", "", def.prompt.preamble.trim(), "");
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
lines.push(
|
|
917
|
+
"### ๐ฌ How to Use",
|
|
918
|
+
"",
|
|
919
|
+
`ๅจไปปๆ issue ๆ MR ไธญ่ฏ่ฎบ \`@${username} <ไฝ ็้ๆฑ>\`๏ผๆไผ่ชๅจๆฅๅๅค็ใ`,
|
|
920
|
+
"",
|
|
921
|
+
"### ๐ Status",
|
|
922
|
+
"",
|
|
923
|
+
`- Provider: \`${def.provider}\``,
|
|
924
|
+
`- Poll interval: ${def.poll_interval_seconds ?? 30}s`,
|
|
925
|
+
"",
|
|
926
|
+
"---",
|
|
927
|
+
`*Auto-updated by [glab-agent](https://www.npmjs.com/package/glab-agent)*`,
|
|
928
|
+
);
|
|
929
|
+
|
|
930
|
+
const content = lines.join("\n");
|
|
931
|
+
|
|
932
|
+
try {
|
|
933
|
+
// Check if profile project exists
|
|
934
|
+
let project = await dependencies.gitlabClient.getProject(projectPath);
|
|
935
|
+
|
|
936
|
+
if (!project) {
|
|
937
|
+
// Create profile project
|
|
938
|
+
project = await dependencies.gitlabClient.createProject(username, {
|
|
939
|
+
visibility: "public",
|
|
940
|
+
initializeWithReadme: true
|
|
941
|
+
});
|
|
942
|
+
logger.info(`Created profile project: ${projectPath}`);
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
// Update or create README
|
|
946
|
+
const existing = await dependencies.gitlabClient.getRepositoryFile(project.id, "README.md");
|
|
947
|
+
await dependencies.gitlabClient.createOrUpdateRepositoryFile(
|
|
948
|
+
project.id,
|
|
949
|
+
"README.md",
|
|
950
|
+
content,
|
|
951
|
+
"Update profile README",
|
|
952
|
+
{ create: !existing }
|
|
953
|
+
);
|
|
954
|
+
logger.info(`Profile README updated: ${projectPath}`);
|
|
955
|
+
} catch (error) {
|
|
956
|
+
logger.info?.(`Profile README update skipped: ${String(error).slice(0, 150)}`);
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
|
|
885
960
|
export async function markAgentOffline(
|
|
886
961
|
_config: LocalAgentConfig,
|
|
887
962
|
gitlabClient: GitlabClient,
|
|
@@ -1264,6 +1339,7 @@ export async function main(argv: string[] = process.argv.slice(2)): Promise<void
|
|
|
1264
1339
|
// Update GitLab user bio with agent profile (P1: Agent = ๅๅทฅ)
|
|
1265
1340
|
await updateAgentUserBio(config, dependencies);
|
|
1266
1341
|
await publishAgentProfileWiki(config, dependencies);
|
|
1342
|
+
await publishProfileReadme(config, dependencies);
|
|
1267
1343
|
await updateAgentUserStatus(dependencies, "idle", undefined, config);
|
|
1268
1344
|
} catch (error) {
|
|
1269
1345
|
logger.error(`Token validation failed for agent "${agentName}": ${String(error)}`);
|