@apolloyh/apollo-agent 0.1.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.
Files changed (103) hide show
  1. package/.apollo/config.example.json +37 -0
  2. package/.env.example +17 -0
  3. package/README.md +62 -0
  4. package/dist/brand.d.ts +17 -0
  5. package/dist/brand.d.ts.map +1 -0
  6. package/dist/brand.js +23 -0
  7. package/dist/cli-args.d.ts +13 -0
  8. package/dist/cli-args.d.ts.map +1 -0
  9. package/dist/cli-args.js +50 -0
  10. package/dist/config.d.ts +13 -0
  11. package/dist/config.d.ts.map +1 -0
  12. package/dist/config.js +190 -0
  13. package/dist/constants/spinner-verbs.d.ts +7 -0
  14. package/dist/constants/spinner-verbs.d.ts.map +1 -0
  15. package/dist/constants/spinner-verbs.js +21 -0
  16. package/dist/coordinator/workflow.d.ts +20 -0
  17. package/dist/coordinator/workflow.d.ts.map +1 -0
  18. package/dist/coordinator/workflow.js +120 -0
  19. package/dist/goal/goal-mode.d.ts +26 -0
  20. package/dist/goal/goal-mode.d.ts.map +1 -0
  21. package/dist/goal/goal-mode.js +141 -0
  22. package/dist/hooks/runner.d.ts +43 -0
  23. package/dist/hooks/runner.d.ts.map +1 -0
  24. package/dist/hooks/runner.js +94 -0
  25. package/dist/index.d.ts +3 -0
  26. package/dist/index.d.ts.map +1 -0
  27. package/dist/index.js +1716 -0
  28. package/dist/llm/anthropic.d.ts +46 -0
  29. package/dist/llm/anthropic.d.ts.map +1 -0
  30. package/dist/llm/anthropic.js +278 -0
  31. package/dist/mcp/manager.d.ts +14 -0
  32. package/dist/mcp/manager.d.ts.map +1 -0
  33. package/dist/mcp/manager.js +93 -0
  34. package/dist/memory/memdir.d.ts +19 -0
  35. package/dist/memory/memdir.d.ts.map +1 -0
  36. package/dist/memory/memdir.js +96 -0
  37. package/dist/plan/plan-mode.d.ts +14 -0
  38. package/dist/plan/plan-mode.d.ts.map +1 -0
  39. package/dist/plan/plan-mode.js +90 -0
  40. package/dist/project-instructions.d.ts +8 -0
  41. package/dist/project-instructions.d.ts.map +1 -0
  42. package/dist/project-instructions.js +33 -0
  43. package/dist/runtime/compaction.d.ts +5 -0
  44. package/dist/runtime/compaction.d.ts.map +1 -0
  45. package/dist/runtime/compaction.js +37 -0
  46. package/dist/runtime/context.d.ts +25 -0
  47. package/dist/runtime/context.d.ts.map +1 -0
  48. package/dist/runtime/context.js +75 -0
  49. package/dist/runtime/permissions.d.ts +11 -0
  50. package/dist/runtime/permissions.d.ts.map +1 -0
  51. package/dist/runtime/permissions.js +119 -0
  52. package/dist/runtime/prompt-builder.d.ts +27 -0
  53. package/dist/runtime/prompt-builder.d.ts.map +1 -0
  54. package/dist/runtime/prompt-builder.js +112 -0
  55. package/dist/runtime/query-engine.d.ts +136 -0
  56. package/dist/runtime/query-engine.d.ts.map +1 -0
  57. package/dist/runtime/query-engine.js +1182 -0
  58. package/dist/runtime/tool-policy.d.ts +13 -0
  59. package/dist/runtime/tool-policy.d.ts.map +1 -0
  60. package/dist/runtime/tool-policy.js +106 -0
  61. package/dist/sdk.d.ts +33 -0
  62. package/dist/sdk.d.ts.map +1 -0
  63. package/dist/sdk.js +41 -0
  64. package/dist/session/resume-ui.d.ts +17 -0
  65. package/dist/session/resume-ui.d.ts.map +1 -0
  66. package/dist/session/resume-ui.js +64 -0
  67. package/dist/session/store.d.ts +66 -0
  68. package/dist/session/store.d.ts.map +1 -0
  69. package/dist/session/store.js +120 -0
  70. package/dist/skillify/skillify.d.ts +12 -0
  71. package/dist/skillify/skillify.d.ts.map +1 -0
  72. package/dist/skillify/skillify.js +52 -0
  73. package/dist/skills/skills.d.ts +26 -0
  74. package/dist/skills/skills.d.ts.map +1 -0
  75. package/dist/skills/skills.js +195 -0
  76. package/dist/status-ui.d.ts +37 -0
  77. package/dist/status-ui.d.ts.map +1 -0
  78. package/dist/status-ui.js +130 -0
  79. package/dist/thought-fold.d.ts +48 -0
  80. package/dist/thought-fold.d.ts.map +1 -0
  81. package/dist/thought-fold.js +156 -0
  82. package/dist/tools/builtin.d.ts +27 -0
  83. package/dist/tools/builtin.d.ts.map +1 -0
  84. package/dist/tools/builtin.js +898 -0
  85. package/dist/tools/registry.d.ts +17 -0
  86. package/dist/tools/registry.d.ts.map +1 -0
  87. package/dist/tools/registry.js +86 -0
  88. package/dist/trace.d.ts +68 -0
  89. package/dist/trace.d.ts.map +1 -0
  90. package/dist/trace.js +600 -0
  91. package/dist/types.d.ts +202 -0
  92. package/dist/types.d.ts.map +1 -0
  93. package/dist/types.js +1 -0
  94. package/dist/utils.d.ts +8 -0
  95. package/dist/utils.d.ts.map +1 -0
  96. package/dist/utils.js +78 -0
  97. package/docs/sdk.md +259 -0
  98. package/package.json +53 -0
  99. package/src/skills/tech-research-skill/SKILL.md +200 -0
  100. package/src/skills/tech-research-skill/agents/openai.yaml +4 -0
  101. package/src/skills/tech-research-skill/repo-analyze +435 -0
  102. package/src/skills/tech-research-skill/repo-fetch +310 -0
  103. package/src/skills/tech-research-skill/report-generate +254 -0
@@ -0,0 +1,141 @@
1
+ /**
2
+ * Goal mode — pursue a user goal until done (open-ended autonomous loop).
3
+ * Differs from fixed 4-phase workflow: steps are free-form; exit via markers or /goal stop.
4
+ */
5
+ export function createGoal(goal, maxIterations = 12, criteria = []) {
6
+ return {
7
+ goal: goal.trim(),
8
+ status: "active",
9
+ criteria,
10
+ progress: [],
11
+ iteration: 0,
12
+ maxIterations,
13
+ startedAt: new Date().toISOString(),
14
+ };
15
+ }
16
+ export function goalStatusBar(g, color) {
17
+ const dim = color ? "\x1b[90m" : "";
18
+ const reset = color ? "\x1b[0m" : "";
19
+ const green = color ? "\x1b[32m" : "";
20
+ const red = color ? "\x1b[31m" : "";
21
+ const yellow = color ? "\x1b[33m" : "";
22
+ const blue = color ? "\x1b[38;2;96;165;250m" : "";
23
+ let mark = "◉";
24
+ let c = yellow;
25
+ if (g.status === "completed") {
26
+ mark = "●";
27
+ c = green;
28
+ }
29
+ else if (g.status === "failed") {
30
+ mark = "●";
31
+ c = red;
32
+ }
33
+ else if (g.status === "blocked" || g.status === "paused") {
34
+ mark = "○";
35
+ c = dim;
36
+ }
37
+ const head = color ? `${blue}Goal${reset}` : "Goal";
38
+ const lines = [
39
+ `\n${head} ${c}${mark} ${g.status}${reset} · iter ${g.iteration}/${g.maxIterations}`,
40
+ `${dim}${g.goal}${reset}`,
41
+ ];
42
+ if (g.criteria.length) {
43
+ lines.push(`${dim}criteria:${reset}`);
44
+ for (const cr of g.criteria.slice(0, 5))
45
+ lines.push(`${dim} · ${cr}${reset}`);
46
+ }
47
+ if (g.progress.length) {
48
+ lines.push(`${dim}progress:${reset}`);
49
+ for (const pr of g.progress.slice(-5))
50
+ lines.push(`${dim} · ${pr}${reset}`);
51
+ }
52
+ if (g.lastBlockedReason) {
53
+ lines.push(`${yellow}blocked: ${g.lastBlockedReason}${reset}`);
54
+ }
55
+ return lines.join("\n") + "\n";
56
+ }
57
+ export function goalSystemExtra(g) {
58
+ const criteria = g.criteria.length > 0
59
+ ? g.criteria.map((c) => `- ${c}`).join("\n")
60
+ : "- Goal is achieved when the user's request is fully satisfied and verified when possible.";
61
+ const progress = g.progress.length > 0
62
+ ? g.progress
63
+ .slice(-8)
64
+ .map((p) => `- ${p}`)
65
+ .join("\n")
66
+ : "- (none yet)";
67
+ return `# Goal Mode (ACTIVE)
68
+ You are autonomously pursuing a **goal**. Keep working until it is done.
69
+
70
+ ## Goal
71
+ ${g.goal}
72
+
73
+ ## Success criteria
74
+ ${criteria}
75
+
76
+ ## Progress so far
77
+ ${progress}
78
+
79
+ ## Iteration
80
+ ${g.iteration} / ${g.maxIterations}
81
+
82
+ ## Rules
83
+ 1. Every turn, make concrete progress (tools, edits, research). Do not only restate the goal.
84
+ 2. Prefer Task(Explore) for research and Task(general-purpose) for implementation when isolation helps.
85
+ 3. After meaningful progress, emit exactly one line:
86
+ GOAL_PROGRESS:<short note of what you did>
87
+ 4. When fully done and verified, emit:
88
+ GOAL_DONE:<one-line summary of outcome>
89
+ 5. If you need the user (missing secret, product choice, destructive confirm), emit:
90
+ GOAL_BLOCKED:<what you need>
91
+ Then stop acting until they reply.
92
+ 6. If impossible after honest effort, emit:
93
+ GOAL_FAILED:<reason>
94
+ 7. Do not claim GOAL_DONE unless criteria are met.
95
+ 8. Keep user-facing text concise; put process detail in tools / progress markers.`;
96
+ }
97
+ /** Parse model markers and update goal state. */
98
+ export function applyGoalMarkers(g, text) {
99
+ let next = { ...g, progress: [...g.progress] };
100
+ for (const m of text.matchAll(/GOAL_PROGRESS:([^\n]+)/g)) {
101
+ const note = (m[1] ?? "").trim();
102
+ if (note)
103
+ next.progress.push(note);
104
+ }
105
+ for (const m of text.matchAll(/GOAL_BLOCKED:([^\n]+)/g)) {
106
+ next = {
107
+ ...next,
108
+ status: "blocked",
109
+ lastBlockedReason: (m[1] ?? "").trim(),
110
+ };
111
+ }
112
+ for (const m of text.matchAll(/GOAL_FAILED:([^\n]+)/g)) {
113
+ next = {
114
+ ...next,
115
+ status: "failed",
116
+ completedAt: new Date().toISOString(),
117
+ lastBlockedReason: (m[1] ?? "").trim(),
118
+ progress: [...next.progress, `failed: ${(m[1] ?? "").trim()}`],
119
+ };
120
+ }
121
+ for (const m of text.matchAll(/GOAL_DONE:([^\n]+)/g)) {
122
+ next = {
123
+ ...next,
124
+ status: "completed",
125
+ completedAt: new Date().toISOString(),
126
+ progress: [...next.progress, `done: ${(m[1] ?? "").trim()}`],
127
+ };
128
+ }
129
+ return next;
130
+ }
131
+ export function shouldAutoContinue(g) {
132
+ return g.status === "active" && g.iteration < g.maxIterations;
133
+ }
134
+ export function nextGoalContinuePrompt(g) {
135
+ return [
136
+ `Continue Goal mode (iteration ${g.iteration + 1}/${g.maxIterations}).`,
137
+ `Goal: ${g.goal}`,
138
+ "Make the next concrete step. Use tools as needed.",
139
+ "End with GOAL_PROGRESS, GOAL_DONE, GOAL_BLOCKED, or GOAL_FAILED as appropriate.",
140
+ ].join("\n");
141
+ }
@@ -0,0 +1,43 @@
1
+ import type { JsonObject, ToolRisk } from "../types.js";
2
+ export type HookDecision = {
3
+ allow: boolean;
4
+ message?: string;
5
+ /** Optional rewritten input */
6
+ input?: JsonObject;
7
+ };
8
+ export type HookEvent = {
9
+ phase: "PreToolUse" | "PostToolUse";
10
+ toolName: string;
11
+ risk: ToolRisk;
12
+ input: JsonObject;
13
+ result?: {
14
+ content: string;
15
+ isError?: boolean;
16
+ };
17
+ };
18
+ export type HookHandler = (event: HookEvent) => Promise<HookDecision | void> | HookDecision | void;
19
+ export type HooksFile = {
20
+ /** Deny tools by name in PreToolUse */
21
+ denyTools?: string[];
22
+ /** Log all tool calls to .apollo/hooks.log */
23
+ log?: boolean;
24
+ /** Custom notes shown when a tool is blocked */
25
+ denyMessage?: string;
26
+ };
27
+ export declare class HookRunner {
28
+ private readonly workspaceRoot;
29
+ private file;
30
+ private handlers;
31
+ private loaded;
32
+ private loadError?;
33
+ constructor(workspaceRoot: string);
34
+ register(handler: HookHandler): void;
35
+ load(): Promise<void>;
36
+ preToolUse(toolName: string, risk: ToolRisk, input: JsonObject): Promise<HookDecision>;
37
+ postToolUse(toolName: string, risk: ToolRisk, input: JsonObject, result: {
38
+ content: string;
39
+ isError?: boolean;
40
+ }): Promise<void>;
41
+ private appendLog;
42
+ }
43
+ //# sourceMappingURL=runner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/hooks/runner.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAGxD,MAAM,MAAM,YAAY,GAAG;IACzB,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,+BAA+B;IAC/B,KAAK,CAAC,EAAE,UAAU,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG;IACtB,KAAK,EAAE,YAAY,GAAG,aAAa,CAAC;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,QAAQ,CAAC;IACf,KAAK,EAAE,UAAU,CAAC;IAClB,MAAM,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;CACjD,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG,CAAC,KAAK,EAAE,SAAS,KAAK,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,GAAG,YAAY,GAAG,IAAI,CAAC;AAEnG,MAAM,MAAM,SAAS,GAAG;IACtB,uCAAuC;IACvC,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,8CAA8C;IAC9C,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,gDAAgD;IAChD,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,qBAAa,UAAU;IAMT,OAAO,CAAC,QAAQ,CAAC,aAAa;IAL1C,OAAO,CAAC,IAAI,CAAiB;IAC7B,OAAO,CAAC,QAAQ,CAAqB;IACrC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,SAAS,CAAC,CAAS;gBAEE,aAAa,EAAE,MAAM;IAElD,QAAQ,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI;IAI9B,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAcrB,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,YAAY,CAAC;IAmBtF,WAAW,CACf,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,QAAQ,EACd,KAAK,EAAE,UAAU,EACjB,MAAM,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,GAC7C,OAAO,CAAC,IAAI,CAAC;YAiBF,SAAS;CAMxB"}
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Tool hooks — PreToolUse / PostToolUse (CC-inspired).
3
+ * Config: .apollo/hooks.json
4
+ */
5
+ import fs from "node:fs/promises";
6
+ import path from "node:path";
7
+ import { safeRealResolve } from "../utils.js";
8
+ export class HookRunner {
9
+ workspaceRoot;
10
+ file = {};
11
+ handlers = [];
12
+ loaded = false;
13
+ loadError;
14
+ constructor(workspaceRoot) {
15
+ this.workspaceRoot = workspaceRoot;
16
+ }
17
+ register(handler) {
18
+ this.handlers.push(handler);
19
+ }
20
+ async load() {
21
+ if (this.loaded)
22
+ return;
23
+ try {
24
+ const file = await safeRealResolve(this.workspaceRoot, path.join(this.workspaceRoot, ".apollo", "hooks.json"));
25
+ const raw = await fs.readFile(file, "utf8");
26
+ this.file = JSON.parse(raw);
27
+ }
28
+ catch (error) {
29
+ if (error.code !== "ENOENT") {
30
+ this.loadError = `Failed to load .apollo/hooks.json: ${error instanceof Error ? error.message : String(error)}`;
31
+ }
32
+ }
33
+ this.loaded = true;
34
+ }
35
+ async preToolUse(toolName, risk, input) {
36
+ await this.load();
37
+ if (this.loadError)
38
+ return { allow: false, message: this.loadError };
39
+ if (this.file.denyTools?.includes(toolName)) {
40
+ return {
41
+ allow: false,
42
+ message: this.file.denyMessage ?? `Hook denied tool: ${toolName}`,
43
+ };
44
+ }
45
+ let currentInput = input;
46
+ for (const h of this.handlers) {
47
+ const d = await h({ phase: "PreToolUse", toolName, risk, input: currentInput });
48
+ if (d && d.allow === false)
49
+ return d;
50
+ if (d?.input)
51
+ currentInput = d.input;
52
+ }
53
+ if (this.file.log)
54
+ await this.appendLog({ phase: "PreToolUse", toolName, risk, input: currentInput });
55
+ return { allow: true, input: currentInput };
56
+ }
57
+ async postToolUse(toolName, risk, input, result) {
58
+ await this.load();
59
+ if (this.loadError)
60
+ return;
61
+ for (const h of this.handlers) {
62
+ await h({ phase: "PostToolUse", toolName, risk, input, result });
63
+ }
64
+ if (this.file.log) {
65
+ await this.appendLog({
66
+ phase: "PostToolUse",
67
+ toolName,
68
+ risk,
69
+ input,
70
+ result: { content: result.content.slice(0, 500), isError: result.isError },
71
+ });
72
+ }
73
+ }
74
+ async appendLog(entry) {
75
+ const dir = await safeRealResolve(this.workspaceRoot, path.join(this.workspaceRoot, ".apollo"));
76
+ await fs.mkdir(dir, { recursive: true });
77
+ const line = `${JSON.stringify(redactLogValue({ ts: new Date().toISOString(), ...entry }))}\n`;
78
+ await fs.appendFile(await safeRealResolve(dir, path.join(dir, "hooks.log")), line, "utf8");
79
+ }
80
+ }
81
+ const SENSITIVE_LOG_KEY = /(?:authorization|password|secret|token|api[_-]?key)/i;
82
+ const PRIVATE_LOG_FIELD = /^(arguments|body|command|content|message|prompt|subject|task|to)$/i;
83
+ function redactLogValue(value, key = "") {
84
+ if (SENSITIVE_LOG_KEY.test(key) || PRIVATE_LOG_FIELD.test(key)) {
85
+ const length = typeof value === "string" ? ` (${value.length} chars)` : "";
86
+ return `[redacted${length}]`;
87
+ }
88
+ if (Array.isArray(value))
89
+ return value.map((item) => redactLogValue(item));
90
+ if (value && typeof value === "object") {
91
+ return Object.fromEntries(Object.entries(value).map(([childKey, childValue]) => [childKey, redactLogValue(childValue, childKey)]));
92
+ }
93
+ return value;
94
+ }
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}