@lawrencehui/citio 0.2.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/.dockerignore +8 -0
- package/Dockerfile +47 -0
- package/LICENSE +21 -0
- package/README.md +305 -0
- package/citio.example.yaml +43 -0
- package/dist/adapters/slack.d.ts +22 -0
- package/dist/adapters/slack.d.ts.map +1 -0
- package/dist/adapters/slack.js +624 -0
- package/dist/adapters/slack.js.map +1 -0
- package/dist/cli/init.d.ts +3 -0
- package/dist/cli/init.d.ts.map +1 -0
- package/dist/cli/init.js +1464 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/cli/ops.d.ts +13 -0
- package/dist/cli/ops.d.ts.map +1 -0
- package/dist/cli/ops.js +167 -0
- package/dist/cli/ops.js.map +1 -0
- package/dist/config/schema.d.ts +81 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +65 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/core/agent-runner.d.ts +38 -0
- package/dist/core/agent-runner.d.ts.map +1 -0
- package/dist/core/agent-runner.js +531 -0
- package/dist/core/agent-runner.js.map +1 -0
- package/dist/core/mcp-entry.d.ts +7 -0
- package/dist/core/mcp-entry.d.ts.map +1 -0
- package/dist/core/mcp-entry.js +390 -0
- package/dist/core/mcp-entry.js.map +1 -0
- package/dist/core/provider-config.d.ts +2 -0
- package/dist/core/provider-config.d.ts.map +1 -0
- package/dist/core/provider-config.js +53 -0
- package/dist/core/provider-config.js.map +1 -0
- package/dist/core/session-manager.d.ts +15 -0
- package/dist/core/session-manager.d.ts.map +1 -0
- package/dist/core/session-manager.js +78 -0
- package/dist/core/session-manager.js.map +1 -0
- package/dist/core/skills.d.ts +24 -0
- package/dist/core/skills.d.ts.map +1 -0
- package/dist/core/skills.js +111 -0
- package/dist/core/skills.js.map +1 -0
- package/dist/core/workspace.d.ts +13 -0
- package/dist/core/workspace.d.ts.map +1 -0
- package/dist/core/workspace.js +238 -0
- package/dist/core/workspace.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +152 -0
- package/dist/index.js.map +1 -0
- package/dist/utils/app-state.d.ts +5 -0
- package/dist/utils/app-state.d.ts.map +1 -0
- package/dist/utils/app-state.js +35 -0
- package/dist/utils/app-state.js.map +1 -0
- package/dist/utils/claude.d.ts +4 -0
- package/dist/utils/claude.d.ts.map +1 -0
- package/dist/utils/claude.js +65 -0
- package/dist/utils/claude.js.map +1 -0
- package/dist/utils/codex.d.ts +5 -0
- package/dist/utils/codex.d.ts.map +1 -0
- package/dist/utils/codex.js +17 -0
- package/dist/utils/codex.js.map +1 -0
- package/dist/utils/env.d.ts +2 -0
- package/dist/utils/env.d.ts.map +1 -0
- package/dist/utils/env.js +16 -0
- package/dist/utils/env.js.map +1 -0
- package/dist/utils/installer-state.d.ts +33 -0
- package/dist/utils/installer-state.d.ts.map +1 -0
- package/dist/utils/installer-state.js +152 -0
- package/dist/utils/installer-state.js.map +1 -0
- package/dist/utils/runtime-env.d.ts +3 -0
- package/dist/utils/runtime-env.d.ts.map +1 -0
- package/dist/utils/runtime-env.js +24 -0
- package/dist/utils/runtime-env.js.map +1 -0
- package/dist/utils/secret-store.d.ts +18 -0
- package/dist/utils/secret-store.d.ts.map +1 -0
- package/dist/utils/secret-store.js +78 -0
- package/dist/utils/secret-store.js.map +1 -0
- package/dist/utils/slack-onboarding.d.ts +22 -0
- package/dist/utils/slack-onboarding.d.ts.map +1 -0
- package/dist/utils/slack-onboarding.js +205 -0
- package/dist/utils/slack-onboarding.js.map +1 -0
- package/package.json +76 -0
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { execSync } from "child_process";
|
|
2
|
+
import { cpSync, existsSync, mkdirSync, mkdtempSync, rmSync } from "fs";
|
|
3
|
+
import os from "os";
|
|
4
|
+
import path from "path";
|
|
5
|
+
// Curated for Citio's job (investigate bugs, read logs, fix code, open PRs).
|
|
6
|
+
// Every install command below is verified working with `npx skills add`.
|
|
7
|
+
export const SKILL_REGISTRY = {
|
|
8
|
+
"systematic-debugging": {
|
|
9
|
+
url: "obra/superpowers --skill systematic-debugging",
|
|
10
|
+
description: "Root-cause debugging discipline — find the bug before patching it",
|
|
11
|
+
installMethod: "npx-skills",
|
|
12
|
+
},
|
|
13
|
+
"code-review": {
|
|
14
|
+
url: "obra/superpowers --skill receiving-code-review",
|
|
15
|
+
description: "Systematic code-review discipline — respond to and act on review feedback",
|
|
16
|
+
installMethod: "npx-skills",
|
|
17
|
+
},
|
|
18
|
+
"webapp-testing": {
|
|
19
|
+
url: "anthropics/skills --skill webapp-testing",
|
|
20
|
+
description: "Official Anthropic: verify fixes by driving the web app in a browser",
|
|
21
|
+
installMethod: "npx-skills",
|
|
22
|
+
},
|
|
23
|
+
"frontend-design": {
|
|
24
|
+
url: "anthropics/claude-code --skill frontend-design",
|
|
25
|
+
description: "Production-grade UI generation, avoids default design patterns",
|
|
26
|
+
installMethod: "npx-skills",
|
|
27
|
+
},
|
|
28
|
+
"skill-creator": {
|
|
29
|
+
url: "anthropics/skills --skill skill-creator",
|
|
30
|
+
description: "Official Anthropic: turn your team's own processes into custom skills",
|
|
31
|
+
installMethod: "npx-skills",
|
|
32
|
+
},
|
|
33
|
+
gstack: {
|
|
34
|
+
url: "https://github.com/garrytan/gstack.git",
|
|
35
|
+
description: "QA, shipping, investigation, deploy, design review",
|
|
36
|
+
installMethod: "git",
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Install skills into `skillsDir` so the runtime's loadSkills() (which reads
|
|
41
|
+
* `<skillsDir>/<name>/SKILL.md`) actually finds them. Idempotent: skills whose
|
|
42
|
+
* SKILL.md already exists are skipped — safe to run on every container boot.
|
|
43
|
+
*
|
|
44
|
+
* npx-skills entries are installed via `npx skills add` into a temp directory
|
|
45
|
+
* (the skills CLI writes to `./.agents/skills/`) and then copied into place,
|
|
46
|
+
* because the skills CLI's layout is not the layout Citio reads.
|
|
47
|
+
*/
|
|
48
|
+
export function installSkillsTo(skillNames, skillsDir, options = {}) {
|
|
49
|
+
const results = [];
|
|
50
|
+
if (skillNames.length === 0)
|
|
51
|
+
return results;
|
|
52
|
+
mkdirSync(skillsDir, { recursive: true });
|
|
53
|
+
for (const skill of skillNames) {
|
|
54
|
+
const info = SKILL_REGISTRY[skill];
|
|
55
|
+
if (!info) {
|
|
56
|
+
results.push({ skill, status: "unknown-skill" });
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
const targetPath = path.join(skillsDir, skill);
|
|
60
|
+
if (existsSync(path.join(targetPath, "SKILL.md"))) {
|
|
61
|
+
results.push({ skill, status: "already-present" });
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
try {
|
|
65
|
+
if (info.installMethod === "git") {
|
|
66
|
+
const authedUrl = options.ghToken
|
|
67
|
+
? info.url.replace("https://github.com/", `https://${options.ghToken}@github.com/`)
|
|
68
|
+
: info.url;
|
|
69
|
+
execSync(`git clone --depth 1 "${authedUrl}" "${targetPath}"`, {
|
|
70
|
+
stdio: "pipe",
|
|
71
|
+
timeout: 120000,
|
|
72
|
+
env: { ...process.env, GIT_TERMINAL_PROMPT: "0" },
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
// npx-skills and legacy npx entries both go through the skills CLI in a
|
|
77
|
+
// sandbox dir, then the produced skill folder is copied into skillsDir.
|
|
78
|
+
const tempDir = mkdtempSync(path.join(os.tmpdir(), "citio-skill-"));
|
|
79
|
+
try {
|
|
80
|
+
execSync(`npx -y skills add ${info.url} -y`, {
|
|
81
|
+
stdio: "pipe",
|
|
82
|
+
cwd: tempDir,
|
|
83
|
+
timeout: 180000,
|
|
84
|
+
});
|
|
85
|
+
const produced = path.join(tempDir, ".agents", "skills", skill);
|
|
86
|
+
if (!existsSync(path.join(produced, "SKILL.md"))) {
|
|
87
|
+
throw new Error(`skills CLI did not produce ${produced}`);
|
|
88
|
+
}
|
|
89
|
+
cpSync(produced, targetPath, { recursive: true });
|
|
90
|
+
}
|
|
91
|
+
finally {
|
|
92
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
results.push({ skill, status: "installed" });
|
|
96
|
+
}
|
|
97
|
+
catch (err) {
|
|
98
|
+
// execSync throws with stdout/stderr buffers when stdio is piped — surface
|
|
99
|
+
// stderr so failures aren't masked by npm's notice noise on stdout.
|
|
100
|
+
const e = err;
|
|
101
|
+
const stderr = e?.stderr ? String(e.stderr).trim().split("\n").filter(Boolean).slice(-3).join(" | ") : "";
|
|
102
|
+
results.push({
|
|
103
|
+
skill,
|
|
104
|
+
status: "failed",
|
|
105
|
+
error: [e?.message, stderr].filter(Boolean).join(" — ").slice(0, 400),
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return results;
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=skills.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skills.js","sourceRoot":"","sources":["../../src/core/skills.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { CitioConfig } from "../config/schema.js";
|
|
2
|
+
export declare class WorkspaceManager {
|
|
3
|
+
private workspacePath;
|
|
4
|
+
private config;
|
|
5
|
+
constructor(config: CitioConfig, workspacePath?: string);
|
|
6
|
+
getMainWorkspacePath(): string;
|
|
7
|
+
initialize(): Promise<void>;
|
|
8
|
+
private generateInstructionFiles;
|
|
9
|
+
private loadSkills;
|
|
10
|
+
private extractRepoName;
|
|
11
|
+
cleanupWorktree(worktreePath: string): void;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=workspace.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspace.d.ts","sourceRoot":"","sources":["../../src/core/workspace.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAGvD,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,MAAM,CAAc;gBAEhB,MAAM,EAAE,WAAW,EAAE,aAAa,SAAe;IAK7D,oBAAoB,IAAI,MAAM;IAIxB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAiIjC,OAAO,CAAC,wBAAwB;IAqEhC,OAAO,CAAC,UAAU;IAkClB,OAAO,CAAC,eAAe;IAOvB,eAAe,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI;CAkB5C"}
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
import { execFileSync, execSync } from "child_process";
|
|
2
|
+
import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from "fs";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import { installSkillsTo } from "./skills.js";
|
|
5
|
+
export class WorkspaceManager {
|
|
6
|
+
workspacePath;
|
|
7
|
+
config;
|
|
8
|
+
constructor(config, workspacePath = "/workspace") {
|
|
9
|
+
this.config = config;
|
|
10
|
+
this.workspacePath = workspacePath;
|
|
11
|
+
}
|
|
12
|
+
getMainWorkspacePath() {
|
|
13
|
+
return this.workspacePath;
|
|
14
|
+
}
|
|
15
|
+
async initialize() {
|
|
16
|
+
mkdirSync(this.workspacePath, { recursive: true });
|
|
17
|
+
try {
|
|
18
|
+
execFileSync("git", ["config", "--global", "user.name", this.config.workspace.git.user_name], {
|
|
19
|
+
stdio: "pipe",
|
|
20
|
+
encoding: "utf-8",
|
|
21
|
+
});
|
|
22
|
+
if (this.config.workspace.git.user_email) {
|
|
23
|
+
execFileSync("git", ["config", "--global", "user.email", this.config.workspace.git.user_email], {
|
|
24
|
+
stdio: "pipe",
|
|
25
|
+
encoding: "utf-8",
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
console.log(JSON.stringify({
|
|
29
|
+
type: "git_identity_configured",
|
|
30
|
+
userName: this.config.workspace.git.user_name,
|
|
31
|
+
userEmail: this.config.workspace.git.user_email || null,
|
|
32
|
+
}));
|
|
33
|
+
}
|
|
34
|
+
catch (err) {
|
|
35
|
+
console.log(JSON.stringify({
|
|
36
|
+
type: "git_identity_configuration_failed",
|
|
37
|
+
error: err instanceof Error ? err.message : String(err),
|
|
38
|
+
}));
|
|
39
|
+
}
|
|
40
|
+
// Configure git to use GH_TOKEN for HTTPS clones
|
|
41
|
+
const ghToken = process.env.GH_TOKEN;
|
|
42
|
+
if (ghToken) {
|
|
43
|
+
try {
|
|
44
|
+
execFileSync("git", ["config", "--global", "credential.helper", `!f() { echo "username=oauth2"; echo "password=${ghToken}"; }; f`], {
|
|
45
|
+
stdio: "pipe",
|
|
46
|
+
encoding: "utf-8",
|
|
47
|
+
});
|
|
48
|
+
console.log(JSON.stringify({ type: "git_credential_configured" }));
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
// Non-fatal, try URL injection as fallback
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
// Ensure workspace is a git repo (Codex requires it)
|
|
55
|
+
if (!existsSync(path.join(this.workspacePath, ".git"))) {
|
|
56
|
+
try {
|
|
57
|
+
execSync("git init", { cwd: this.workspacePath, stdio: "pipe" });
|
|
58
|
+
console.log(JSON.stringify({ type: "workspace_git_init" }));
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
// Non-fatal
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
for (const repo of this.config.workspace.repos) {
|
|
65
|
+
const repoName = this.extractRepoName(repo.url);
|
|
66
|
+
const repoPath = path.join(this.workspacePath, repoName);
|
|
67
|
+
// Inject token into URL as fallback for credential helper
|
|
68
|
+
const cloneUrl = ghToken
|
|
69
|
+
? repo.url.replace("https://github.com/", `https://${ghToken}@github.com/`)
|
|
70
|
+
: repo.url;
|
|
71
|
+
if (existsSync(repoPath)) {
|
|
72
|
+
console.log(JSON.stringify({
|
|
73
|
+
type: "workspace_pull",
|
|
74
|
+
repo: repoName,
|
|
75
|
+
}));
|
|
76
|
+
try {
|
|
77
|
+
execSync(`git pull --ff-only`, {
|
|
78
|
+
cwd: repoPath,
|
|
79
|
+
encoding: "utf-8",
|
|
80
|
+
timeout: 60000,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
catch (err) {
|
|
84
|
+
console.log(JSON.stringify({
|
|
85
|
+
type: "workspace_pull_failed",
|
|
86
|
+
repo: repoName,
|
|
87
|
+
error: err instanceof Error ? err.message : String(err),
|
|
88
|
+
}));
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
console.log(JSON.stringify({
|
|
93
|
+
type: "workspace_clone",
|
|
94
|
+
repo: repoName,
|
|
95
|
+
url: repo.url,
|
|
96
|
+
}));
|
|
97
|
+
try {
|
|
98
|
+
execSync(`git clone --depth 1 --branch "${repo.branch}" "${cloneUrl}" "${repoPath}"`, {
|
|
99
|
+
encoding: "utf-8",
|
|
100
|
+
timeout: 300000,
|
|
101
|
+
env: { ...process.env, GIT_TERMINAL_PROMPT: "0" },
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
catch (err) {
|
|
105
|
+
console.log(JSON.stringify({
|
|
106
|
+
type: "workspace_clone_failed",
|
|
107
|
+
repo: repoName,
|
|
108
|
+
error: err instanceof Error ? err.message : String(err),
|
|
109
|
+
}));
|
|
110
|
+
// Don't crash — continue with other repos
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
// Install configured skills into the directory loadSkills() reads.
|
|
116
|
+
// Idempotent (skips already-present skills), non-fatal on failure —
|
|
117
|
+
// this is how skills reach the container, which local installs cannot.
|
|
118
|
+
const configuredSkills = this.config.skills?.installed ?? [];
|
|
119
|
+
if (configuredSkills.length > 0) {
|
|
120
|
+
const results = installSkillsTo(configuredSkills, this.config.skills.directory, { ghToken });
|
|
121
|
+
for (const result of results) {
|
|
122
|
+
console.log(JSON.stringify({ type: "skill_install", ...result }));
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
this.generateInstructionFiles();
|
|
126
|
+
}
|
|
127
|
+
generateInstructionFiles() {
|
|
128
|
+
const skills = this.loadSkills();
|
|
129
|
+
// User-configured rules from citio.yaml, falling back to the defaults.
|
|
130
|
+
const configuredRules = this.config.workspace?.rules ?? [];
|
|
131
|
+
const rules = configuredRules.length > 0 ? configuredRules : [
|
|
132
|
+
"Always create PRs for code changes. Never push directly to main.",
|
|
133
|
+
"When investigating bugs, check logs first before making code changes.",
|
|
134
|
+
"Report findings back to the team with clear summaries.",
|
|
135
|
+
];
|
|
136
|
+
const baseInstructionContent = `# Citio Agent Instructions
|
|
137
|
+
|
|
138
|
+
## Rules
|
|
139
|
+
${rules.map((rule) => `- ${rule}`).join("\n")}
|
|
140
|
+
- After any update or change pushed to a PR, always quote the PR link in your response.
|
|
141
|
+
|
|
142
|
+
## Available MCP Tools
|
|
143
|
+
You have access to these tools via the MCP server:
|
|
144
|
+
- investigate_codebase: Search code for patterns
|
|
145
|
+
- read_file: Read file contents
|
|
146
|
+
- write_file: Create or edit files
|
|
147
|
+
- create_branch: Create a git branch with isolated worktree
|
|
148
|
+
- create_pr: Open a pull request on GitHub
|
|
149
|
+
- run_command: Run allowlisted commands (git, npm, tsc, etc.)
|
|
150
|
+
- check_ci_status: Check CI/CD status of a PR
|
|
151
|
+
- save_finding: Save learnings to org memory
|
|
152
|
+
- recall_context: Search saved org memory for prior findings
|
|
153
|
+
- query_logs: Query CloudWatch logs from the task role
|
|
154
|
+
- post_update: Record a progress update for the current Slack thread
|
|
155
|
+
- query_audit_log: Search the recorded MCP tool audit trail
|
|
156
|
+
|
|
157
|
+
## Workflow
|
|
158
|
+
0. For simple status/info questions (what's running, service health, quick lookups):
|
|
159
|
+
answer with MINIMAL tool calls (1-3) — skip recall_context, skip query_audit_log,
|
|
160
|
+
don't chain tools you don't need. Speed matters more than ceremony.
|
|
161
|
+
0b. When asked about a resource BY NAME (a service, cluster, app) and you don't find
|
|
162
|
+
an exact match: enumerate before asking back — e.g. list all ECS clusters, then
|
|
163
|
+
list services in each, and fuzzy-match ("Aegis" ~ aegis-bastion, "Bifrost" ~
|
|
164
|
+
bifrost-app). People use short names; infrastructure uses long ones. Only ask
|
|
165
|
+
the user when enumeration genuinely finds no plausible match.
|
|
166
|
+
1. When asked to investigate a bug, use investigate_codebase and read_file first
|
|
167
|
+
2. For CloudWatch or AWS checks, use query_logs first and only use run_command when query_logs is not enough
|
|
168
|
+
3. Prefer these MCP tools over native Bash/Grep/Glob/Read tools whenever possible
|
|
169
|
+
4. Use post_update for meaningful progress checkpoints, not every trivial step
|
|
170
|
+
5. Use recall_context before starting non-trivial investigations, not for simple questions
|
|
171
|
+
6. Create a branch before making changes
|
|
172
|
+
7. Create a PR when your fix is ready
|
|
173
|
+
8. Save any important findings with save_finding`;
|
|
174
|
+
const instructionContent = skills
|
|
175
|
+
? `${baseInstructionContent}\n\n${skills}\n`
|
|
176
|
+
: `${baseInstructionContent}\n`;
|
|
177
|
+
// Write CLAUDE.md for Claude Code
|
|
178
|
+
writeFileSync(path.join(this.workspacePath, "CLAUDE.md"), instructionContent, "utf-8");
|
|
179
|
+
// Write AGENTS.md for Codex
|
|
180
|
+
writeFileSync(path.join(this.workspacePath, "AGENTS.md"), instructionContent, "utf-8");
|
|
181
|
+
}
|
|
182
|
+
loadSkills() {
|
|
183
|
+
const skillsDir = this.config.skills.directory;
|
|
184
|
+
if (!existsSync(skillsDir))
|
|
185
|
+
return "";
|
|
186
|
+
const entries = readdirSync(skillsDir, { withFileTypes: true });
|
|
187
|
+
const index = [];
|
|
188
|
+
for (const entry of entries) {
|
|
189
|
+
if (!entry.isDirectory())
|
|
190
|
+
continue;
|
|
191
|
+
const skillPath = path.join(skillsDir, entry.name, "SKILL.md");
|
|
192
|
+
if (!existsSync(skillPath))
|
|
193
|
+
continue;
|
|
194
|
+
// Progressive disclosure: inlining full SKILL.md bodies added ~60KB to
|
|
195
|
+
// EVERY agent request (verified: multi-minute responses). Give the agent
|
|
196
|
+
// a one-line index and let it read the file when the task matches.
|
|
197
|
+
const content = readFileSync(skillPath, "utf-8");
|
|
198
|
+
let description = "";
|
|
199
|
+
const fmMatch = content.match(/^---\n[\s\S]*?\bdescription:\s*(.+)/m);
|
|
200
|
+
if (fmMatch)
|
|
201
|
+
description = fmMatch[1].trim().replace(/^["']|["']$/g, "");
|
|
202
|
+
if (!description) {
|
|
203
|
+
const body = content.replace(/^---\n[\s\S]*?\n---\n?/, "");
|
|
204
|
+
description = (body.split("\n").find((line) => line.trim() && !line.trim().startsWith("#")) || "").trim().slice(0, 200);
|
|
205
|
+
}
|
|
206
|
+
index.push(`- **${entry.name}** — ${description}\n Full instructions: read \`${skillPath}\``);
|
|
207
|
+
}
|
|
208
|
+
if (index.length === 0)
|
|
209
|
+
return "";
|
|
210
|
+
return (`\n# Installed Skills\n\n` +
|
|
211
|
+
`These skills are installed on disk. When a task matches one, READ its SKILL.md (path below) and follow it — do not guess its contents:\n\n` +
|
|
212
|
+
index.join("\n"));
|
|
213
|
+
}
|
|
214
|
+
extractRepoName(url) {
|
|
215
|
+
return url
|
|
216
|
+
.split("/")
|
|
217
|
+
.pop()
|
|
218
|
+
.replace(/\.git$/, "");
|
|
219
|
+
}
|
|
220
|
+
cleanupWorktree(worktreePath) {
|
|
221
|
+
try {
|
|
222
|
+
const repoDir = path.dirname(worktreePath);
|
|
223
|
+
execSync(`git worktree remove "${worktreePath}" --force`, {
|
|
224
|
+
cwd: repoDir,
|
|
225
|
+
encoding: "utf-8",
|
|
226
|
+
timeout: 30000,
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
catch (err) {
|
|
230
|
+
console.log(JSON.stringify({
|
|
231
|
+
type: "worktree_cleanup_failed",
|
|
232
|
+
path: worktreePath,
|
|
233
|
+
error: err instanceof Error ? err.message : String(err),
|
|
234
|
+
}));
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
//# sourceMappingURL=workspace.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspace.js","sourceRoot":"","sources":["../../src/core/workspace.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,eAAe,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import "dotenv/config";
|
|
2
|
+
import { randomUUID } from "crypto";
|
|
3
|
+
import { readFileSync } from "fs";
|
|
4
|
+
import { parse } from "yaml";
|
|
5
|
+
import { CitioConfigSchema } from "./config/schema.js";
|
|
6
|
+
import { WorkspaceManager } from "./core/workspace.js";
|
|
7
|
+
import { AgentRunner } from "./core/agent-runner.js";
|
|
8
|
+
import { SessionManager } from "./core/session-manager.js";
|
|
9
|
+
import { SlackAdapter } from "./adapters/slack.js";
|
|
10
|
+
import { resolveEnvVars } from "./utils/env.js";
|
|
11
|
+
import { formatCodexAuthHint, getCodexAuthPath, hasCodexCredentials } from "./utils/codex.js";
|
|
12
|
+
import { createServer } from "http";
|
|
13
|
+
async function main() {
|
|
14
|
+
const configPath = process.env.CITIO_CONFIG || "citio.yaml";
|
|
15
|
+
let rawConfig;
|
|
16
|
+
try {
|
|
17
|
+
let raw;
|
|
18
|
+
if (process.env.CITIO_CONFIG_B64) {
|
|
19
|
+
// Config passed as base64 env var (for ECS without volume mounts)
|
|
20
|
+
raw = Buffer.from(process.env.CITIO_CONFIG_B64, "base64").toString("utf-8");
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
raw = readFileSync(configPath, "utf-8");
|
|
24
|
+
}
|
|
25
|
+
rawConfig = resolveEnvVars(parse(raw));
|
|
26
|
+
}
|
|
27
|
+
catch (err) {
|
|
28
|
+
console.error(`Failed to read config at ${configPath}:`, err);
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
31
|
+
const config = CitioConfigSchema.parse(rawConfig);
|
|
32
|
+
const workspacePath = process.env.CITIO_WORKSPACE || "/workspace";
|
|
33
|
+
console.log(JSON.stringify({
|
|
34
|
+
type: "startup",
|
|
35
|
+
name: config.name,
|
|
36
|
+
provider: config.engine.default_provider,
|
|
37
|
+
channel: config.slack.channel_id,
|
|
38
|
+
workspace: workspacePath,
|
|
39
|
+
repos: config.workspace.repos.length,
|
|
40
|
+
skills: config.skills.installed.length,
|
|
41
|
+
}));
|
|
42
|
+
// Refresh Codex tokens on startup (id_token expires every hour)
|
|
43
|
+
if (config.engine.default_provider === "codex") {
|
|
44
|
+
const fs = await import("fs");
|
|
45
|
+
const home = process.env.HOME || "/home/citio";
|
|
46
|
+
const authPath = getCodexAuthPath(home);
|
|
47
|
+
console.log(JSON.stringify({
|
|
48
|
+
type: "codex_auth_check",
|
|
49
|
+
home,
|
|
50
|
+
authPath,
|
|
51
|
+
hasAuthFile: fs.existsSync(authPath),
|
|
52
|
+
hasApiKey: Boolean(process.env.OPENAI_API_KEY),
|
|
53
|
+
}));
|
|
54
|
+
if (!hasCodexCredentials()) {
|
|
55
|
+
console.log(JSON.stringify({
|
|
56
|
+
type: "codex_auth_missing",
|
|
57
|
+
message: formatCodexAuthHint(home),
|
|
58
|
+
}));
|
|
59
|
+
}
|
|
60
|
+
try {
|
|
61
|
+
const authData = JSON.parse(fs.readFileSync(authPath, "utf-8"));
|
|
62
|
+
const refreshToken = authData?.tokens?.refresh_token;
|
|
63
|
+
if (refreshToken) {
|
|
64
|
+
console.log(JSON.stringify({ type: "token_refresh", status: "refreshing" }));
|
|
65
|
+
const { execSync: ex } = await import("child_process");
|
|
66
|
+
const resp = ex(`curl -s -X POST "https://auth.openai.com/oauth/token" -H "Content-Type: application/json" -d '{"grant_type":"refresh_token","refresh_token":"${refreshToken}","client_id":"app_EMoamEEZ73f0CkXaXp7hrann"}'`, { encoding: "utf-8", timeout: 15000 });
|
|
67
|
+
const fresh = JSON.parse(resp);
|
|
68
|
+
if (fresh.id_token && fresh.access_token) {
|
|
69
|
+
authData.tokens.id_token = fresh.id_token;
|
|
70
|
+
authData.tokens.access_token = fresh.access_token;
|
|
71
|
+
if (fresh.refresh_token)
|
|
72
|
+
authData.tokens.refresh_token = fresh.refresh_token;
|
|
73
|
+
fs.writeFileSync(authPath, JSON.stringify(authData, null, 2));
|
|
74
|
+
console.log(JSON.stringify({ type: "token_refresh", status: "success" }));
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
console.log(JSON.stringify({ type: "token_refresh", status: "failed", error: JSON.stringify(fresh) }));
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
catch (err) {
|
|
82
|
+
console.log(JSON.stringify({ type: "token_refresh", status: "error", error: err instanceof Error ? err.message : String(err) }));
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
if (config.engine.default_provider === "claude" && !process.env.ANTHROPIC_API_KEY) {
|
|
86
|
+
console.log(JSON.stringify({
|
|
87
|
+
type: "claude_auth_mode",
|
|
88
|
+
message: process.env.CLAUDE_CODE_OAUTH_TOKEN
|
|
89
|
+
? "Claude will run without --bare using CLAUDE_CODE_OAUTH_TOKEN."
|
|
90
|
+
: "Claude will run without --bare so it can use non-API-key Claude auth.",
|
|
91
|
+
}));
|
|
92
|
+
}
|
|
93
|
+
// Initialize workspace
|
|
94
|
+
const workspace = new WorkspaceManager(config, workspacePath);
|
|
95
|
+
await workspace.initialize();
|
|
96
|
+
// Initialize agent runner (long-running MCP server for Codex, or -p for Claude)
|
|
97
|
+
const agentRunner = new AgentRunner(config, workspacePath);
|
|
98
|
+
await agentRunner.start();
|
|
99
|
+
const runtimeId = randomUUID();
|
|
100
|
+
console.log(JSON.stringify({ type: "runtime_session_scope", runtimeId }));
|
|
101
|
+
const sessionManager = new SessionManager(config.engine.default_provider, process.env.CITIO_MEMORY || "/memory", runtimeId);
|
|
102
|
+
// Health check server
|
|
103
|
+
const healthServer = createServer((req, res) => {
|
|
104
|
+
if (req.url === "/healthz") {
|
|
105
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
106
|
+
res.end(JSON.stringify({
|
|
107
|
+
status: "ok",
|
|
108
|
+
agentRunning: agentRunner.isRunning,
|
|
109
|
+
queueLength: agentRunner.queueLength,
|
|
110
|
+
provider: config.engine.default_provider,
|
|
111
|
+
}));
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
res.writeHead(404);
|
|
115
|
+
res.end();
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
healthServer.listen(3001, () => {
|
|
119
|
+
console.log(JSON.stringify({ type: "health_check", port: 3001 }));
|
|
120
|
+
});
|
|
121
|
+
// Provider tuning from citio.yaml -> env (explicit env vars still win).
|
|
122
|
+
const codexProvider = config.engine.providers?.codex;
|
|
123
|
+
const claudeProvider = config.engine.providers?.claude;
|
|
124
|
+
if (codexProvider?.model && !process.env.CODEX_MODEL)
|
|
125
|
+
process.env.CODEX_MODEL = codexProvider.model;
|
|
126
|
+
if (codexProvider?.reasoning_effort && !process.env.CODEX_REASONING_EFFORT)
|
|
127
|
+
process.env.CODEX_REASONING_EFFORT = codexProvider.reasoning_effort;
|
|
128
|
+
if (claudeProvider?.model && !process.env.CLAUDE_MODEL)
|
|
129
|
+
process.env.CLAUDE_MODEL = claudeProvider.model;
|
|
130
|
+
// Start Slack adapter
|
|
131
|
+
const slack = new SlackAdapter(config, agentRunner, sessionManager);
|
|
132
|
+
await slack.start();
|
|
133
|
+
console.log(JSON.stringify({ type: "ready" }));
|
|
134
|
+
// Graceful shutdown
|
|
135
|
+
const shutdown = async (signal) => {
|
|
136
|
+
console.log(JSON.stringify({ type: "shutdown", signal }));
|
|
137
|
+
// Tell any thread with an in-flight task that we're restarting — the
|
|
138
|
+
// provider process dies with the container and would otherwise go silent.
|
|
139
|
+
await Promise.race([slack.notifyShutdown(), new Promise((r) => setTimeout(r, 3000))]);
|
|
140
|
+
await Promise.race([slack.stop(), new Promise((r) => setTimeout(r, 10000))]);
|
|
141
|
+
healthServer.close();
|
|
142
|
+
console.log(JSON.stringify({ type: "shutdown_complete" }));
|
|
143
|
+
process.exit(0);
|
|
144
|
+
};
|
|
145
|
+
process.on("SIGTERM", () => shutdown("SIGTERM"));
|
|
146
|
+
process.on("SIGINT", () => shutdown("SIGINT"));
|
|
147
|
+
}
|
|
148
|
+
main().catch((err) => {
|
|
149
|
+
console.error("Fatal error:", err);
|
|
150
|
+
process.exit(1);
|
|
151
|
+
});
|
|
152
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare function getCitioStateDir(): string;
|
|
2
|
+
export declare function getInstallerStatePath(): string;
|
|
3
|
+
export declare function getFallbackSecretsPath(): string;
|
|
4
|
+
export declare function pathExists(filePath: string): boolean;
|
|
5
|
+
//# sourceMappingURL=app-state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-state.d.ts","sourceRoot":"","sources":["../../src/utils/app-state.ts"],"names":[],"mappings":"AAcA,wBAAgB,gBAAgB,IAAI,MAAM,CAczC;AAED,wBAAgB,qBAAqB,IAAI,MAAM,CAE9C;AAED,wBAAgB,sBAAsB,IAAI,MAAM,CAE/C;AAED,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAEpD"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { chmodSync, existsSync, mkdirSync } from "fs";
|
|
2
|
+
import os from "os";
|
|
3
|
+
import path from "path";
|
|
4
|
+
function ensureDir(dirPath) {
|
|
5
|
+
mkdirSync(dirPath, { recursive: true, mode: 0o700 });
|
|
6
|
+
try {
|
|
7
|
+
chmodSync(dirPath, 0o700);
|
|
8
|
+
}
|
|
9
|
+
catch {
|
|
10
|
+
// Best-effort only.
|
|
11
|
+
}
|
|
12
|
+
return dirPath;
|
|
13
|
+
}
|
|
14
|
+
export function getCitioStateDir() {
|
|
15
|
+
const homeDir = os.homedir();
|
|
16
|
+
if (process.platform === "darwin") {
|
|
17
|
+
return ensureDir(path.join(homeDir, "Library", "Application Support", "Citio"));
|
|
18
|
+
}
|
|
19
|
+
if (process.platform === "win32") {
|
|
20
|
+
const appData = process.env.APPDATA || path.join(homeDir, "AppData", "Roaming");
|
|
21
|
+
return ensureDir(path.join(appData, "Citio"));
|
|
22
|
+
}
|
|
23
|
+
const xdgConfigHome = process.env.XDG_CONFIG_HOME || path.join(homeDir, ".config");
|
|
24
|
+
return ensureDir(path.join(xdgConfigHome, "citio"));
|
|
25
|
+
}
|
|
26
|
+
export function getInstallerStatePath() {
|
|
27
|
+
return path.join(getCitioStateDir(), "installer-state.yaml");
|
|
28
|
+
}
|
|
29
|
+
export function getFallbackSecretsPath() {
|
|
30
|
+
return path.join(getCitioStateDir(), "secrets.json");
|
|
31
|
+
}
|
|
32
|
+
export function pathExists(filePath) {
|
|
33
|
+
return existsSync(filePath);
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=app-state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-state.js","sourceRoot":"","sources":["../../src/utils/app-state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AACtD,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,SAAS,SAAS,CAAC,OAAe;IAChC,SAAS,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACrD,IAAI,CAAC;QACH,SAAS,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IAC5B,CAAC;IAAC,MAAM,CAAC;QACP,oBAAoB;IACtB,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,gBAAgB;IAC9B,MAAM,OAAO,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC;IAE7B,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAClC,OAAO,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,EAAE,qBAAqB,EAAE,OAAO,CAAC,CAAC,CAAC;IAClF,CAAC;IAED,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACjC,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;QAChF,OAAO,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;IAChD,CAAC;IAED,MAAM,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IACnF,OAAO,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC,CAAC;AACtD,CAAC;AAED,MAAM,UAAU,qBAAqB;IACnC,OAAO,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,EAAE,sBAAsB,CAAC,CAAC;AAC/D,CAAC;AAED,MAAM,UAAU,sBAAsB;IACpC,OAAO,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,EAAE,cAAc,CAAC,CAAC;AACvD,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,QAAgB;IACzC,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC;AAC9B,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare function normalizeClaudeOauthToken(token: string): string;
|
|
2
|
+
export declare function extractClaudeOauthTokenFromTranscript(transcriptPath: string): string | null;
|
|
3
|
+
export declare function validateClaudeOauthToken(token: string): boolean;
|
|
4
|
+
//# sourceMappingURL=claude.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude.d.ts","sourceRoot":"","sources":["../../src/utils/claude.ts"],"names":[],"mappings":"AAOA,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAI/D;AASD,wBAAgB,qCAAqC,CAAC,cAAc,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CA0B3F;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CA4B/D"}
|