alp-code 0.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.
Files changed (204) hide show
  1. package/CHANGELOG.md +770 -0
  2. package/LICENSE +21 -0
  3. package/README.md +295 -0
  4. package/alp.config.yaml +5 -0
  5. package/dist/src/agents/agent-definition.js +28 -0
  6. package/dist/src/agents/capability-catalog.js +33 -0
  7. package/dist/src/agents/compaction.js +36 -0
  8. package/dist/src/agents/errors.js +12 -0
  9. package/dist/src/agents/librarian.js +38 -0
  10. package/dist/src/agents/main.js +37 -0
  11. package/dist/src/agents/memory-grant.js +29 -0
  12. package/dist/src/agents/model-context.js +70 -0
  13. package/dist/src/agents/modes.js +134 -0
  14. package/dist/src/agents/oracle.js +36 -0
  15. package/dist/src/agents/read-thread.js +38 -0
  16. package/dist/src/agents/registry.js +238 -0
  17. package/dist/src/agents/render-identity.js +38 -0
  18. package/dist/src/agents/review.js +37 -0
  19. package/dist/src/agents/search.js +37 -0
  20. package/dist/src/agents/shared/house-rules.js +33 -0
  21. package/dist/src/agents/shared/principal.js +18 -0
  22. package/dist/src/agents/shared/voice.js +29 -0
  23. package/dist/src/agents/titling.js +32 -0
  24. package/dist/src/agents/types.js +15 -0
  25. package/dist/src/backend/execution-backend.js +2 -0
  26. package/dist/src/backend/local-execution-store.js +144 -0
  27. package/dist/src/backend/local-process-backend.js +533 -0
  28. package/dist/src/backend/local-supervisor.js +104 -0
  29. package/dist/src/cli/alp.js +380 -0
  30. package/dist/src/cli/commands/context.js +203 -0
  31. package/dist/src/cli/commands/delegate.js +136 -0
  32. package/dist/src/cli/commands/identity-sync.js +31 -0
  33. package/dist/src/cli/commands/init.js +184 -0
  34. package/dist/src/cli/commands/mode.js +22 -0
  35. package/dist/src/cli/commands/principal.js +114 -0
  36. package/dist/src/cli/commands/run-main.js +90 -0
  37. package/dist/src/cli/commands/runtime.js +21 -0
  38. package/dist/src/cli/mode-preference-store.js +62 -0
  39. package/dist/src/cli/mode-selector.js +178 -0
  40. package/dist/src/cli/update-check.js +77 -0
  41. package/dist/src/context/checkpoint.js +134 -0
  42. package/dist/src/context/compact-journal.js +153 -0
  43. package/dist/src/context/compact-payload.js +121 -0
  44. package/dist/src/context/continuity.js +70 -0
  45. package/dist/src/context/types.js +2 -0
  46. package/dist/src/delegation/backend-registry.js +40 -0
  47. package/dist/src/delegation/delegation-service.js +300 -0
  48. package/dist/src/delegation/types.js +12 -0
  49. package/dist/src/execution/execution-policy.js +96 -0
  50. package/dist/src/execution/execution-service.js +115 -0
  51. package/dist/src/execution/execution-store.js +78 -0
  52. package/dist/src/execution/identity-capsule.js +65 -0
  53. package/dist/src/execution/types.js +12 -0
  54. package/dist/src/hooks/execution-bridge.js +84 -0
  55. package/dist/src/index.js +4 -0
  56. package/dist/src/memory/adapters/markdown-file-store.js +257 -0
  57. package/dist/src/memory/adapters/memory-api-client.js +2 -0
  58. package/dist/src/memory/adapters/memory-path-mapper.js +76 -0
  59. package/dist/src/memory/adapters/remote-api-store.js +25 -0
  60. package/dist/src/memory/context-ranker.js +21 -0
  61. package/dist/src/memory/errors.js +58 -0
  62. package/dist/src/memory/memory-service.js +149 -0
  63. package/dist/src/memory/memory-store.js +2 -0
  64. package/dist/src/memory/types.js +2 -0
  65. package/dist/src/policy/capability-policy.js +29 -0
  66. package/dist/src/policy/delegation-policy.js +25 -0
  67. package/dist/src/policy/errors.js +10 -0
  68. package/dist/src/policy/invariants.js +31 -0
  69. package/dist/src/policy/memory-policy.js +22 -0
  70. package/dist/src/policy/policy-engine.js +85 -0
  71. package/dist/src/policy/types.js +8 -0
  72. package/dist/src/policy/workspace-policy.js +77 -0
  73. package/dist/src/principal/principal-profile-store.js +89 -0
  74. package/dist/src/runtime/adapter-files.js +147 -0
  75. package/dist/src/runtime/claude-adapter.js +177 -0
  76. package/dist/src/runtime/codex-adapter.js +169 -0
  77. package/dist/src/runtime/permission-rules.js +156 -0
  78. package/dist/src/runtime/render-session-context.js +124 -0
  79. package/dist/src/runtime/render-task-input.js +33 -0
  80. package/dist/src/runtime/runtime-adapter.js +2 -0
  81. package/dist/src/runtime/runtime-preference-store.js +66 -0
  82. package/dist/src/runtime/runtime-selector.js +178 -0
  83. package/dist/src/runtime/types.js +2 -0
  84. package/dist/src/runtime/windows-shim.js +57 -0
  85. package/dist/src/state-paths.js +49 -0
  86. package/dist/src/workflow/output-validator.js +27 -0
  87. package/dist/src/workflow/repair-policy.js +8 -0
  88. package/dist/src/workflow/types.js +22 -0
  89. package/dist/src/workflow/workflow-runner.js +81 -0
  90. package/hooks/compact-record.cjs +109 -0
  91. package/hooks/session-boot.cjs +112 -0
  92. package/hooks/session-end.cjs +34 -0
  93. package/package.json +48 -0
  94. package/scaffold/memory/INDEX.md +27 -0
  95. package/scaffold/memory/README.md +76 -0
  96. package/scaffold/memory/projects/INDEX.md +22 -0
  97. package/scaffold/memory/projects/PROTOCOL.md +128 -0
  98. package/scaffold/memory/projects/_template/PROJECT.md +45 -0
  99. package/scripts/alp.cjs +126 -0
  100. package/scripts/alp.ps1 +4 -0
  101. package/scripts/alp.sh +3 -0
  102. package/scripts/bootstrap.cjs +144 -0
  103. package/scripts/checkout-release.cjs +30 -0
  104. package/scripts/delegate.cjs +19 -0
  105. package/scripts/doctor.cjs +158 -0
  106. package/scripts/doctor.sh +3 -0
  107. package/scripts/ensure-state.cjs +22 -0
  108. package/scripts/lib/cli-link.cjs +375 -0
  109. package/scripts/lib/codex-role.cjs +18 -0
  110. package/scripts/lib/delegation/command-runner.cjs +108 -0
  111. package/scripts/lib/delegation/config.cjs +81 -0
  112. package/scripts/lib/install-paths.cjs +154 -0
  113. package/scripts/lib/release-manifest.cjs +42 -0
  114. package/scripts/lib/semver-lite.cjs +20 -0
  115. package/scripts/lib/state.cjs +274 -0
  116. package/scripts/lib/uninstall.cjs +252 -0
  117. package/scripts/lib/update-check-worker.cjs +21 -0
  118. package/scripts/lib/update.cjs +395 -0
  119. package/scripts/run-role.cjs +42 -0
  120. package/scripts/run-role.ps1 +4 -0
  121. package/scripts/run-role.sh +3 -0
  122. package/scripts/sync-project-index.sh +167 -0
  123. package/skills/agent-memory/SKILL.md +109 -0
  124. package/skills/alp-debug/SKILL.md +90 -0
  125. package/skills/alp-debug/references/defense-in-depth.md +118 -0
  126. package/skills/alp-debug/references/investigation-methodology.md +106 -0
  127. package/skills/alp-debug/references/log-and-ci-analysis.md +96 -0
  128. package/skills/alp-debug/references/performance-diagnostics.md +112 -0
  129. package/skills/alp-debug/references/reporting-standards.md +120 -0
  130. package/skills/alp-debug/references/root-cause-tracing.md +134 -0
  131. package/skills/alp-debug/references/systematic-debugging.md +93 -0
  132. package/skills/alp-debug/references/verification.md +86 -0
  133. package/skills/alp-debug/scripts/find-polluter.sh +63 -0
  134. package/skills/alp-debug/scripts/find-polluter.test.md +102 -0
  135. package/skills/alp-plan/SKILL.md +128 -0
  136. package/skills/alp-plan/references/archive-workflow.md +77 -0
  137. package/skills/alp-plan/references/codebase-understanding.md +55 -0
  138. package/skills/alp-plan/references/output-standards.md +96 -0
  139. package/skills/alp-plan/references/plan-organization.md +129 -0
  140. package/skills/alp-plan/references/red-team-personas.md +76 -0
  141. package/skills/alp-plan/references/red-team-workflow.md +81 -0
  142. package/skills/alp-plan/references/research-phase.md +57 -0
  143. package/skills/alp-plan/references/scope-challenge.md +82 -0
  144. package/skills/alp-plan/references/solution-design.md +76 -0
  145. package/skills/alp-plan/references/validate-question-framework.md +89 -0
  146. package/skills/alp-plan/references/validate-workflow.md +83 -0
  147. package/skills/alp-predict/SKILL.md +98 -0
  148. package/skills/alp-scenario/SKILL.md +86 -0
  149. package/skills/code-review/SKILL.md +111 -0
  150. package/skills/code-review/references/code-review-reception.md +114 -0
  151. package/skills/code-review/references/edge-case-scouting.md +78 -0
  152. package/skills/code-review/references/verification-before-completion.md +117 -0
  153. package/skills/delegation/SKILL.md +46 -0
  154. package/skills/docs-seeker/.env.example +15 -0
  155. package/skills/docs-seeker/SKILL.md +87 -0
  156. package/skills/docs-seeker/package.json +25 -0
  157. package/skills/docs-seeker/references/advanced.md +82 -0
  158. package/skills/docs-seeker/references/context7-patterns.md +68 -0
  159. package/skills/docs-seeker/references/errors.md +72 -0
  160. package/skills/docs-seeker/scripts/analyze-llms-txt.js +211 -0
  161. package/skills/docs-seeker/scripts/detect-topic.js +172 -0
  162. package/skills/docs-seeker/scripts/fetch-docs.js +213 -0
  163. package/skills/docs-seeker/scripts/tests/run-tests.js +72 -0
  164. package/skills/docs-seeker/scripts/tests/test-analyze-llms.js +119 -0
  165. package/skills/docs-seeker/scripts/tests/test-detect-topic.js +112 -0
  166. package/skills/docs-seeker/scripts/tests/test-fetch-docs.js +84 -0
  167. package/skills/docs-seeker/scripts/utils/env-loader.js +94 -0
  168. package/skills/docs-seeker/workflows/library-search.md +73 -0
  169. package/skills/docs-seeker/workflows/repo-analysis.md +90 -0
  170. package/skills/docs-seeker/workflows/topic-search.md +69 -0
  171. package/skills/git/SKILL.md +121 -0
  172. package/skills/git/references/branch-management.md +90 -0
  173. package/skills/git/references/commit-standards.md +82 -0
  174. package/skills/git/references/gh-cli-guide.md +132 -0
  175. package/skills/git/references/safety-protocols.md +86 -0
  176. package/skills/git/references/workflow-commit.md +89 -0
  177. package/skills/git/references/workflow-merge.md +63 -0
  178. package/skills/git/references/workflow-pr.md +70 -0
  179. package/skills/git/references/workflow-push.md +62 -0
  180. package/skills/gkg/SKILL.md +87 -0
  181. package/skills/gkg/references/cli-commands.md +92 -0
  182. package/skills/gkg/references/http-api.md +99 -0
  183. package/skills/gkg/references/language-support.md +54 -0
  184. package/skills/problem-solving/SKILL.md +86 -0
  185. package/skills/problem-solving/references/attribution.md +48 -0
  186. package/skills/problem-solving/references/collision-zone-thinking.md +71 -0
  187. package/skills/problem-solving/references/inversion-exercise.md +88 -0
  188. package/skills/problem-solving/references/meta-pattern-recognition.md +80 -0
  189. package/skills/problem-solving/references/scale-game.md +82 -0
  190. package/skills/problem-solving/references/simplification-cascades.md +83 -0
  191. package/skills/problem-solving/references/when-stuck.md +76 -0
  192. package/skills/repomix/SKILL.md +94 -0
  193. package/skills/repomix/references/configuration.md +134 -0
  194. package/skills/repomix/references/usage-patterns.md +106 -0
  195. package/skills/repomix/scripts/.coverage +0 -0
  196. package/skills/repomix/scripts/README.md +179 -0
  197. package/skills/repomix/scripts/repomix_batch.py +455 -0
  198. package/skills/repomix/scripts/repos.example.json +15 -0
  199. package/skills/repomix/scripts/requirements.txt +15 -0
  200. package/skills/repomix/scripts/tests/test_repomix_batch.py +531 -0
  201. package/skills/research/SKILL.md +107 -0
  202. package/skills/security-scan/SKILL.md +101 -0
  203. package/skills/security-scan/references/secret-patterns.md +75 -0
  204. package/skills/security-scan/references/vulnerability-patterns.md +136 -0
@@ -0,0 +1,380 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseAlpArgs = parseAlpArgs;
4
+ exports.main = main;
5
+ const node_crypto_1 = require("node:crypto");
6
+ const node_child_process_1 = require("node:child_process");
7
+ const node_fs_1 = require("node:fs");
8
+ const node_module_1 = require("node:module");
9
+ const node_path_1 = require("node:path");
10
+ const modes_1 = require("../agents/modes");
11
+ const registry_1 = require("../agents/registry");
12
+ const local_process_backend_1 = require("../backend/local-process-backend");
13
+ const execution_service_1 = require("../execution/execution-service");
14
+ const execution_store_1 = require("../execution/execution-store");
15
+ const markdown_file_store_1 = require("../memory/adapters/markdown-file-store");
16
+ const memory_service_1 = require("../memory/memory-service");
17
+ const policy_engine_1 = require("../policy/policy-engine");
18
+ const claude_adapter_1 = require("../runtime/claude-adapter");
19
+ const codex_adapter_1 = require("../runtime/codex-adapter");
20
+ const mode_selector_1 = require("./mode-selector");
21
+ const workflow_runner_1 = require("../workflow/workflow-runner");
22
+ const context_1 = require("./commands/context");
23
+ const delegate_1 = require("./commands/delegate");
24
+ const identity_sync_1 = require("./commands/identity-sync");
25
+ const init_1 = require("./commands/init");
26
+ const principal_1 = require("./commands/principal");
27
+ const run_main_1 = require("./commands/run-main");
28
+ const mode_1 = require("./commands/mode");
29
+ const state_paths_1 = require("../state-paths");
30
+ const update_check_1 = require("./update-check");
31
+ /** Lời nhắn cho mọi chỗ còn gọi runtime — cờ, subcommand, hay tên CLI trần. */
32
+ const RUNTIME_IS_GONE = "runtime không còn là lựa chọn: nấc quyết định model, model quyết định CLI — dùng `alp --mode <nấc>` hoặc `alp mode set <nấc>`";
33
+ /**
34
+ * `alp [--mode <nấc>]` — một cờ duy nhất. Gõ sai thì dừng ngay chứ không rơi về mặc định, vì
35
+ * một phiên chạy nấc khác nấc người dùng tưởng là im lặng tốn tiền hoặc im lặng yếu đi.
36
+ */
37
+ function parseRunMainFlags(argv) {
38
+ let mode;
39
+ for (let index = 0; index < argv.length; index += 1) {
40
+ const value = argv[index];
41
+ if (value === "--runtime" || value.startsWith("--runtime="))
42
+ throw new Error(RUNTIME_IS_GONE);
43
+ if (value !== "--mode" && !value.startsWith("--mode=")) {
44
+ throw new Error(`unknown option \`${value}\`; usage: alp [--mode ${modes_1.MODE_IDS.join("|")}]`);
45
+ }
46
+ let raw;
47
+ if (value === "--mode") {
48
+ raw = argv[index + 1];
49
+ index += 1;
50
+ }
51
+ else {
52
+ raw = value.slice("--mode=".length);
53
+ }
54
+ if (mode !== undefined)
55
+ throw new Error("multiple mode selections are not allowed");
56
+ if (raw === undefined || raw === "")
57
+ throw new Error("alp --mode accepts exactly one mode");
58
+ mode = (0, modes_1.parseMode)(raw);
59
+ }
60
+ return { command: "run-main", ...(mode ? { mode } : {}) };
61
+ }
62
+ function parseAlpArgs(argv) {
63
+ if (argv.length === 0)
64
+ return { command: "run-main" };
65
+ if (argv[0].startsWith("--mode") || argv[0].startsWith("--runtime"))
66
+ return parseRunMainFlags(argv);
67
+ if (argv[0] === "--version" || argv[0] === "-v") {
68
+ if (argv.length !== 1)
69
+ throw new Error("alp --version does not accept arguments");
70
+ return { command: "version" };
71
+ }
72
+ if (["claude", "codex", "run-role"].includes(argv[0]) || argv[0] === "--role") {
73
+ throw new Error("direct raw runtime launch is unsupported; use `alp` or `alp --mode <nấc>`");
74
+ }
75
+ if (argv[0] === "runtime")
76
+ throw new Error(RUNTIME_IS_GONE);
77
+ if (argv[0] === "mode") {
78
+ if (argv[1] === "show" && argv.length === 2)
79
+ return { command: "mode", action: "show" };
80
+ if (argv[1] === "set" && argv.length === 3)
81
+ return { command: "mode", action: "set", mode: (0, modes_1.parseMode)(argv[2]) };
82
+ throw new Error(`usage: alp mode show | alp mode set <${modes_1.MODE_IDS.join("|")}>`);
83
+ }
84
+ if (argv[0] === "init") {
85
+ let project;
86
+ for (let index = 1; index < argv.length; index += 1) {
87
+ const value = argv[index];
88
+ if (value.startsWith("-"))
89
+ throw new Error(`unknown init option \`${value}\``);
90
+ if (project !== undefined)
91
+ throw new Error("alp init accepts one project path");
92
+ project = value;
93
+ }
94
+ return { command: "init", ...(project ? { project } : {}) };
95
+ }
96
+ if (argv[0] === "deinit") {
97
+ if (argv.length > 2 || argv[1]?.startsWith("-"))
98
+ throw new Error("usage: alp deinit [path]");
99
+ return { command: "deinit", ...(argv[1] ? { project: argv[1] } : {}) };
100
+ }
101
+ if (argv[0] === "identity") {
102
+ if (argv[1] === "sync" && argv.length === 2)
103
+ return { command: "identity", action: "sync" };
104
+ throw new Error("usage: alp identity sync");
105
+ }
106
+ if (argv[0] === "principal") {
107
+ if ((argv[1] === "show" || argv[1] === "set") && argv.length === 2) {
108
+ return { command: "principal", action: argv[1] };
109
+ }
110
+ throw new Error("usage: alp principal show | alp principal set");
111
+ }
112
+ if (argv[0] === "delegate")
113
+ return { command: "delegate", args: Object.freeze(argv.slice(1)) };
114
+ if (argv[0] === "delegation")
115
+ return { command: "delegation", args: Object.freeze(argv.slice(1)) };
116
+ if (argv[0] === "context")
117
+ return { command: "context", args: Object.freeze(argv.slice(1)) };
118
+ if (argv[0] === "doctor") {
119
+ if (argv.slice(1).some((value) => value !== "--quiet"))
120
+ throw new Error("usage: alp doctor [--quiet]");
121
+ return { command: "maintenance", action: "doctor", args: Object.freeze(argv.slice(1)) };
122
+ }
123
+ if (argv[0] === "update") {
124
+ if (argv.length !== 1)
125
+ throw new Error("alp update does not accept arguments");
126
+ return { command: "maintenance", action: "update", args: Object.freeze([]) };
127
+ }
128
+ if (argv[0] === "uninstall") {
129
+ if (argv.slice(1).some((value) => value !== "--purge-memory" && value !== "--force")) {
130
+ throw new Error("usage: alp uninstall [--purge-memory] [--force]");
131
+ }
132
+ return { command: "maintenance", action: "uninstall", args: Object.freeze(argv.slice(1)) };
133
+ }
134
+ if (argv[0] === "help" || argv[0] === "--help" || argv[0] === "-h")
135
+ return { command: "help" };
136
+ throw new Error(`unknown command \`${argv[0]}\``);
137
+ }
138
+ function findRepoRoot(start) {
139
+ let directory = (0, node_path_1.resolve)(start);
140
+ for (;;) {
141
+ try {
142
+ (0, node_fs_1.accessSync)((0, node_path_1.join)(directory, "package.json"));
143
+ return directory;
144
+ }
145
+ catch { /* continue */ }
146
+ const parent = (0, node_path_1.dirname)(directory);
147
+ if (parent === directory)
148
+ throw new Error("cannot locate alp-code repository root");
149
+ directory = parent;
150
+ }
151
+ }
152
+ function readVersion(repoRoot) {
153
+ try {
154
+ const parsed = JSON.parse((0, node_fs_1.readFileSync)((0, node_path_1.join)(repoRoot, "package.json"), "utf8"));
155
+ return typeof parsed?.version === "string" ? parsed.version : "0.0.0";
156
+ }
157
+ catch {
158
+ return "0.0.0";
159
+ }
160
+ }
161
+ function defaultDependencies(cwd, stdout, stderr) {
162
+ const repoRoot = process.env.ALP_REPO_ROOT || findRepoRoot(__dirname);
163
+ const version = readVersion(repoRoot);
164
+ const policy = new policy_engine_1.PolicyEngine({ registry: registry_1.agentRegistry });
165
+ const memory = new memory_service_1.MemoryService({
166
+ store: new markdown_file_store_1.MarkdownFileStore({ root: (0, state_paths_1.memoryRoot)() }),
167
+ policy,
168
+ audit: { record() { } },
169
+ });
170
+ const executionService = new execution_service_1.ExecutionService({
171
+ registry: registry_1.agentRegistry,
172
+ policy,
173
+ memory,
174
+ workflowRunner: new workflow_runner_1.WorkflowRunner(),
175
+ store: new execution_store_1.FileExecutionStore({ root: (0, state_paths_1.executionsDirectory)() }),
176
+ });
177
+ const adapters = new Map([
178
+ ["claude", new claude_adapter_1.ClaudeRuntimeAdapter({ hooksDirectory: (0, node_path_1.join)(repoRoot, "hooks") })],
179
+ // Previously left to default to `ALP_REPO_ROOT` (set by `scripts/alp.cjs`) the way
180
+ // Claude's constructor already falls back too. That implicit path was fine carrying two
181
+ // hooks; wiring two more onto it (PreCompact/PostCompact) turns a coincidence into a
182
+ // real dependency, so it is passed explicitly here like Claude's.
183
+ ["codex", new codex_adapter_1.CodexRuntimeAdapter({ hooksDirectory: (0, node_path_1.join)(repoRoot, "hooks") })],
184
+ ]);
185
+ const backend = new local_process_backend_1.LocalProcessBackend();
186
+ const selector = new mode_selector_1.ModeSelector({ output: stdout });
187
+ const projectRegistry = new init_1.ProjectRegistryStore();
188
+ return {
189
+ cwd,
190
+ stdout,
191
+ stderr,
192
+ version,
193
+ async checkForUpdate() {
194
+ if (process.env.ALP_SKIP_UPDATE_CHECK === "1")
195
+ return null;
196
+ try {
197
+ return await (0, update_check_1.checkForUpdate)({ repoRoot, store: new update_check_1.FileUpdateCheckStore(), currentVersion: version });
198
+ }
199
+ catch {
200
+ return null;
201
+ }
202
+ },
203
+ async runMain(input) {
204
+ const result = await (0, run_main_1.runMainSession)(input, {
205
+ registry: registry_1.agentRegistry,
206
+ selector,
207
+ executionService,
208
+ adapters,
209
+ backend,
210
+ executionId: () => `exec_${(0, node_crypto_1.randomUUID)().replaceAll("-", "").slice(0, 20)}`,
211
+ interactive: Boolean(process.stdin.isTTY && process.stdout.isTTY),
212
+ workspaceModeFor: async (project) => (await projectRegistry.isRegistered(project))
213
+ ? "workspace-write"
214
+ : "read-only",
215
+ });
216
+ return result.status === "completed" ? 0 : result.status === "cancelled" ? 130 : 1;
217
+ },
218
+ async modeCommand(input) {
219
+ await (0, mode_1.runModeCommand)(input, { write: (text) => stdout.write(text) });
220
+ return 0;
221
+ },
222
+ async initProject(input) {
223
+ const registered = await (0, init_1.initializeProject)({ ...input, repoRoot }, { store: projectRegistry });
224
+ // Asked before the identity sync below, because the answers are rendered into every
225
+ // `.alp/agents/<role>.md` this install writes.
226
+ await (0, principal_1.ensurePrincipalProfile)({ interactive: Boolean(process.stdin.isTTY && process.stdout.isTTY) }, { write: (text) => stdout.write(text) });
227
+ // Identity documents are what the SessionStart hook reads; a project registered
228
+ // without them would boot with an empty identity and a warning.
229
+ await (0, identity_sync_1.syncIdentityDocuments)({ directory: (0, state_paths_1.agentsDirectory)() }, { registry: registry_1.agentRegistry });
230
+ stdout.write(`READY ${registered.path}\n`);
231
+ },
232
+ async deinitProject(input) {
233
+ await (0, init_1.deinitializeProject)({ ...input, repoRoot }, { store: projectRegistry });
234
+ stdout.write(`REMOVED ${(0, node_path_1.resolve)(input.project)}\n`);
235
+ },
236
+ async syncIdentity() {
237
+ const written = await (0, identity_sync_1.syncIdentityDocuments)({ directory: (0, state_paths_1.agentsDirectory)() }, { registry: registry_1.agentRegistry });
238
+ for (const file of written)
239
+ stdout.write(`IDENTITY ${file}\n`);
240
+ },
241
+ async principalCommand(input) {
242
+ return (0, principal_1.runPrincipalCommand)(input, {
243
+ write: (text) => stdout.write(text),
244
+ // A changed name must reach the generated identity documents, or the next native
245
+ // session would boot with the previous one.
246
+ syncIdentity: async () => { await (0, identity_sync_1.syncIdentityDocuments)({ directory: (0, state_paths_1.agentsDirectory)() }, { registry: registry_1.agentRegistry }); },
247
+ });
248
+ },
249
+ async delegateCommand(args) {
250
+ const lifecycle = args[0] === "__lifecycle";
251
+ const actual = lifecycle ? args.slice(1) : args;
252
+ const composition = await (0, delegate_1.createDefaultDelegationComposition)(repoRoot, process.env);
253
+ const value = lifecycle
254
+ ? await (0, delegate_1.runDelegationLifecycleCommand)(actual, composition.service)
255
+ : await (0, delegate_1.runDelegateCommand)(actual, { cwd, env: process.env, service: composition.service });
256
+ stdout.write(`${JSON.stringify(value, null, 2)}\n`);
257
+ return typeof value === "object" && value !== null && "status" in value && value.status === "failed" ? 1 : 0;
258
+ },
259
+ async contextCommand(args) {
260
+ return (0, context_1.runContextCommand)(args, {
261
+ executionsRoot: (0, state_paths_1.executionsDirectory)(),
262
+ env: process.env,
263
+ write: (text) => stdout.write(text),
264
+ });
265
+ },
266
+ async maintenanceCommand(input) {
267
+ if (input.action === "doctor") {
268
+ const checked = (0, node_child_process_1.spawnSync)(process.execPath, [(0, node_path_1.join)(repoRoot, "scripts", "doctor.cjs"), ...input.args], {
269
+ cwd,
270
+ env: process.env,
271
+ stdio: "inherit",
272
+ });
273
+ if (checked.error)
274
+ throw checked.error;
275
+ return checked.status ?? 2;
276
+ }
277
+ if (input.action === "update") {
278
+ const updater = (0, node_module_1.createRequire)(__filename)((0, node_path_1.join)(repoRoot, "scripts", "lib", "update.cjs"));
279
+ const result = await updater.updateInstallation(repoRoot, {
280
+ env: process.env,
281
+ stdio: "inherit",
282
+ log(level, message) { stdout.write(`${level.padEnd(9)}${message}\n`); },
283
+ });
284
+ if (!result.ok)
285
+ stderr.write(`ERROR ${result.message ?? "update failed"}\n`);
286
+ return result.ok ? 0 : 1;
287
+ }
288
+ const uninstall = (0, node_module_1.createRequire)(__filename)((0, node_path_1.join)(repoRoot, "scripts", "lib", "uninstall.cjs"));
289
+ const result = uninstall.uninstall(repoRoot, {
290
+ cwd,
291
+ purgeMemory: input.args.includes("--purge-memory"),
292
+ force: input.args.includes("--force"),
293
+ });
294
+ for (const entry of result.log)
295
+ stdout.write(`${entry.level.padEnd(8)} ${entry.text}\n`);
296
+ if (result.memoryBackup)
297
+ stdout.write(`RESTORE ${result.memoryBackup}\n`);
298
+ return 0;
299
+ },
300
+ };
301
+ }
302
+ function helpText() {
303
+ return [
304
+ "alp — code-native agent launcher",
305
+ "",
306
+ ` alp [--mode ${modes_1.MODE_IDS.join("|")}]`,
307
+ " alp mode show|set <mode>",
308
+ " alp init [path]",
309
+ " alp deinit [path]",
310
+ " alp identity sync",
311
+ " alp principal show|set",
312
+ " alp delegate <role> [options] -- <task>",
313
+ " alp context status|validate [execution-id]",
314
+ " alp context pin <decision|constraint|open-item|next-action> -- <text>",
315
+ " alp context unpin <pin-id>",
316
+ " alp doctor",
317
+ " alp update [--verbose]",
318
+ " alp uninstall [--purge-memory] [--force]",
319
+ " alp --version",
320
+ "",
321
+ "Mode quyết định model của từng vai, và model quyết định CLI nào chạy vai đó.",
322
+ "Thứ tự: --mode → ALP_MODE → `alp mode set` → hỏi trên TTY → `medium`.",
323
+ "",
324
+ ...modes_1.MODE_IDS.map((mode) => ` ${mode.padEnd(7)} ${modes_1.MODE_PROFILES[mode].summary}`),
325
+ "",
326
+ "Direct `claude`, `codex`, and identity-aware raw-runtime shortcuts are unsupported.",
327
+ ].join("\n") + "\n";
328
+ }
329
+ async function main(argv = process.argv.slice(2), injected) {
330
+ const cwd = injected?.cwd ?? process.cwd();
331
+ const stdout = injected?.stdout ?? process.stdout;
332
+ const stderr = injected?.stderr ?? process.stderr;
333
+ const dependencies = injected ?? defaultDependencies(cwd, stdout, stderr);
334
+ const command = parseAlpArgs(argv);
335
+ const notice = await dependencies.checkForUpdate().catch(() => null);
336
+ if (notice)
337
+ stdout.write(notice);
338
+ if (command.command === "version") {
339
+ stdout.write(`alp ${dependencies.version}\n`);
340
+ return 0;
341
+ }
342
+ if (command.command === "run-main") {
343
+ // Cờ thắng biến môi trường; `ALP_MODE` tồn tại để một phiên delegated kế thừa nấc của cha.
344
+ const inheritedMode = process.env.ALP_MODE ? (0, modes_1.parseMode)(process.env.ALP_MODE) : undefined;
345
+ const mode = command.mode ?? inheritedMode;
346
+ return dependencies.runMain({ cwd, ...(mode ? { mode } : {}) });
347
+ }
348
+ if (command.command === "mode")
349
+ return dependencies.modeCommand(command);
350
+ if (command.command === "init") {
351
+ await dependencies.initProject({ project: (0, node_path_1.resolve)(cwd, command.project ?? ".") });
352
+ return 0;
353
+ }
354
+ if (command.command === "deinit") {
355
+ await dependencies.deinitProject({ project: (0, node_path_1.resolve)(cwd, command.project ?? ".") });
356
+ return 0;
357
+ }
358
+ if (command.command === "identity") {
359
+ await dependencies.syncIdentity();
360
+ return 0;
361
+ }
362
+ if (command.command === "principal")
363
+ return dependencies.principalCommand({ action: command.action });
364
+ if (command.command === "delegate")
365
+ return dependencies.delegateCommand(command.args);
366
+ if (command.command === "delegation")
367
+ return dependencies.delegateCommand(Object.freeze(["__lifecycle", ...command.args]));
368
+ if (command.command === "context")
369
+ return dependencies.contextCommand(command.args);
370
+ if (command.command === "maintenance")
371
+ return dependencies.maintenanceCommand({ action: command.action, args: command.args });
372
+ stdout.write(helpText());
373
+ return 0;
374
+ }
375
+ if (require.main === module) {
376
+ main().then((code) => { process.exitCode = code; }, (error) => {
377
+ process.stderr.write(`ERROR ${error instanceof Error ? error.message : String(error)}\n`);
378
+ process.exitCode = 2;
379
+ });
380
+ }
@@ -0,0 +1,203 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runContextCommand = runContextCommand;
4
+ const node_crypto_1 = require("node:crypto");
5
+ const promises_1 = require("node:fs/promises");
6
+ const node_path_1 = require("node:path");
7
+ const checkpoint_1 = require("../../context/checkpoint");
8
+ const compact_journal_1 = require("../../context/compact-journal");
9
+ const continuity_1 = require("../../context/continuity");
10
+ const adapter_files_1 = require("../../runtime/adapter-files");
11
+ const claude_adapter_1 = require("../../runtime/claude-adapter");
12
+ const codex_adapter_1 = require("../../runtime/codex-adapter");
13
+ const EXECUTION_ID_PATTERN = /^exec_[a-zA-Z0-9_-]+$/;
14
+ const PIN_KINDS = ["decision", "constraint", "open-item", "next-action"];
15
+ const PIN_FIELD = {
16
+ decision: "decisions",
17
+ constraint: "constraints",
18
+ "open-item": "openItems",
19
+ "next-action": "nextActions",
20
+ };
21
+ const USAGE = "usage: alp context status|validate [execution-id] | alp context pin <decision|constraint|open-item|next-action> -- <text> | alp context unpin <pin-id>";
22
+ function isPinKind(value) {
23
+ return PIN_KINDS.includes(value ?? "");
24
+ }
25
+ /** Positional first, `ALP_DELEGATION_EXECUTION_ID` second — no ambiguous "latest" guess. */
26
+ function resolveExecutionId(positional, env) {
27
+ const id = positional || env.ALP_DELEGATION_EXECUTION_ID;
28
+ if (!id)
29
+ throw new Error(USAGE);
30
+ if (!EXECUTION_ID_PATTERN.test(id))
31
+ throw new Error(`invalid execution ID \`${id}\``);
32
+ return id;
33
+ }
34
+ function contextPaths(executionsRoot, executionId) {
35
+ const directory = (0, node_path_1.join)(executionsRoot, executionId);
36
+ const contextDirectory = (0, node_path_1.join)(directory, "context");
37
+ return {
38
+ policyFile: (0, node_path_1.join)(directory, "policy.json"),
39
+ checkpointFile: (0, node_path_1.join)(contextDirectory, "checkpoint.json"),
40
+ continuityFile: (0, node_path_1.join)(contextDirectory, "continuity.md"),
41
+ compactEventsFile: (0, node_path_1.join)(contextDirectory, "compact-events.jsonl"),
42
+ };
43
+ }
44
+ async function readPolicyHash(executionId, policyFile) {
45
+ let raw;
46
+ try {
47
+ raw = await (0, promises_1.readFile)(policyFile, "utf8");
48
+ }
49
+ catch (error) {
50
+ throw new Error(`execution \`${executionId}\` not found: ${error.message}`);
51
+ }
52
+ const parsed = JSON.parse(raw);
53
+ if (typeof parsed.policyHash !== "string" || parsed.policyHash.length === 0) {
54
+ throw new Error(`policy file carries no policyHash: ${policyFile}`);
55
+ }
56
+ return parsed.policyHash;
57
+ }
58
+ /**
59
+ * Reuses the same pinned capability each adapter already carries rather than keeping a
60
+ * second copy of it here — a version bump that changes `sessionStartAfterCompact` only ever
61
+ * has to be made in one place.
62
+ */
63
+ function compactCapabilityFor(runtime) {
64
+ return runtime === "claude" ? new claude_adapter_1.ClaudeRuntimeAdapter().compact : new codex_adapter_1.CodexRuntimeAdapter().compact;
65
+ }
66
+ async function commandStatus(argv, dependencies) {
67
+ const executionId = resolveExecutionId(argv[0], dependencies.env);
68
+ const paths = contextPaths(dependencies.executionsRoot, executionId);
69
+ const policyHash = await readPolicyHash(executionId, paths.policyFile);
70
+ await (0, compact_journal_1.rotateCompactJournalIfNeeded)(paths.compactEventsFile);
71
+ const replay = await (0, compact_journal_1.replayCompactJournal)(paths.compactEventsFile);
72
+ const state = (0, compact_journal_1.reduceCompactJournal)(replay.events);
73
+ const checkpointResult = await (0, checkpoint_1.readCheckpoint)(paths.checkpointFile, { executionId, policyHash });
74
+ const write = dependencies.write;
75
+ write(`EXECUTION ${executionId}\n`);
76
+ if (checkpointResult.ok) {
77
+ const checkpoint = checkpointResult.value;
78
+ write(`OBJECTIVE ${checkpoint.objective ?? "(none)"}\n`);
79
+ write(`PINS decisions=${checkpoint.decisions.length} constraints=${checkpoint.constraints.length} `
80
+ + `open-items=${checkpoint.openItems.length} next-actions=${checkpoint.nextActions.length}\n`);
81
+ }
82
+ else {
83
+ // Fail closed per invariant 6: this is the same reason a runtime would refuse to inject
84
+ // it, surfaced here instead of silently.
85
+ write(`WARNING checkpoint not usable: ${checkpointResult.reason}\n`);
86
+ }
87
+ write(`GENERATION ${state.generation}\n`);
88
+ write(`PENDING ${state.pending ? `${state.pending.runtime} ${state.pending.trigger} (started ${state.pending.observedAt})` : "(none)"}\n`);
89
+ write(`COMPLETED ${state.lastCompleted ? `${state.lastCompleted.runtime} ${state.lastCompleted.trigger} (at ${state.lastCompleted.observedAt})` : "(none)"}\n`);
90
+ const observedRuntime = state.pending?.runtime ?? state.lastCompleted?.runtime ?? null;
91
+ const restore = observedRuntime === null
92
+ ? "unknown — no compaction observed yet"
93
+ : compactCapabilityFor(observedRuntime).sessionStartAfterCompact
94
+ ? "reinjected at the next SessionStart"
95
+ : "next-session (persist-only; this runtime does not reinject)";
96
+ write(`RESTORE ${restore}\n`);
97
+ if (replay.droppedLines > 0)
98
+ write(`WARNING journal has ${replay.droppedLines} line(s) that failed to parse and were skipped\n`);
99
+ return 0;
100
+ }
101
+ async function commandValidate(argv, dependencies) {
102
+ const executionId = resolveExecutionId(argv[0], dependencies.env);
103
+ const paths = contextPaths(dependencies.executionsRoot, executionId);
104
+ const policyHash = await readPolicyHash(executionId, paths.policyFile);
105
+ await (0, compact_journal_1.rotateCompactJournalIfNeeded)(paths.compactEventsFile);
106
+ const replay = await (0, compact_journal_1.replayCompactJournal)(paths.compactEventsFile);
107
+ const state = (0, compact_journal_1.reduceCompactJournal)(replay.events);
108
+ // Reducing twice over the same events is the cheapest possible regression guard for
109
+ // invariant 14 (idempotent lifecycle) — the function is pure, so a mismatch here would mean
110
+ // a real bug, not noise.
111
+ const stable = JSON.stringify(state) === JSON.stringify((0, compact_journal_1.reduceCompactJournal)(replay.events));
112
+ const checkpointResult = await (0, checkpoint_1.readCheckpoint)(paths.checkpointFile, { executionId, policyHash });
113
+ const write = dependencies.write;
114
+ write(`EXECUTION ${executionId}\n`);
115
+ write(`CHECKPOINT ${checkpointResult.ok ? "valid" : `INVALID — ${checkpointResult.reason}`}\n`);
116
+ write(`JOURNAL ${replay.events.length} event(s), ${replay.droppedLines} dropped line(s)\n`);
117
+ write(`REPLAY ${stable ? "stable" : "UNSTABLE"}\n`);
118
+ write(`GENERATION ${state.generation}\n`);
119
+ return checkpointResult.ok && stable ? 0 : 1;
120
+ }
121
+ /** A pin is one sentence: control characters (newlines included) collapse to a single space. */
122
+ function sanitizePinText(raw) {
123
+ return raw.replace(/[\x00-\x1F\x7F]/g, " ").replace(/\s+/g, " ").trim();
124
+ }
125
+ async function loadCheckpointForMutation(executionId, paths, action) {
126
+ const policyHash = await readPolicyHash(executionId, paths.policyFile);
127
+ const result = await (0, checkpoint_1.readCheckpoint)(paths.checkpointFile, { executionId, policyHash });
128
+ if (!result.ok)
129
+ throw new Error(`cannot ${action}: ${result.reason}`);
130
+ return result.value;
131
+ }
132
+ async function persistCheckpoint(paths, checkpoint) {
133
+ const written = await (0, checkpoint_1.writeCheckpoint)(paths.checkpointFile, checkpoint);
134
+ await (0, adapter_files_1.atomicRuntimeFile)(paths.continuityFile, (0, continuity_1.renderContinuity)(written));
135
+ return written;
136
+ }
137
+ async function commandPin(argv, dependencies) {
138
+ const kind = argv[0];
139
+ if (!isPinKind(kind))
140
+ throw new Error(USAGE);
141
+ const separator = argv.indexOf("--");
142
+ if (separator === -1 || separator === argv.length - 1)
143
+ throw new Error(USAGE);
144
+ const text = sanitizePinText(argv.slice(separator + 1).join(" "));
145
+ if (text.length === 0)
146
+ throw new Error("pin text is empty after sanitizing control characters");
147
+ if (Buffer.byteLength(text, "utf8") > checkpoint_1.PIN_MAX_BYTES)
148
+ throw new Error(`pin text exceeds ${checkpoint_1.PIN_MAX_BYTES} bytes`);
149
+ const executionId = resolveExecutionId(undefined, dependencies.env);
150
+ const paths = contextPaths(dependencies.executionsRoot, executionId);
151
+ const checkpoint = await loadCheckpointForMutation(executionId, paths, "pin");
152
+ const now = (dependencies.now ?? (() => new Date().toISOString()))();
153
+ const pin = {
154
+ id: (0, node_crypto_1.randomUUID)(),
155
+ text,
156
+ source: dependencies.env.ALP_DELEGATED_ROLE ? "agent" : "principal",
157
+ createdAt: now,
158
+ };
159
+ const field = PIN_FIELD[kind];
160
+ await persistCheckpoint(paths, { ...checkpoint, [field]: [...checkpoint[field], pin], updatedAt: now });
161
+ dependencies.write(`PINNED ${pin.id}\n`);
162
+ return 0;
163
+ }
164
+ async function commandUnpin(argv, dependencies) {
165
+ const pinId = argv[0];
166
+ if (!pinId)
167
+ throw new Error(USAGE);
168
+ const executionId = resolveExecutionId(undefined, dependencies.env);
169
+ const paths = contextPaths(dependencies.executionsRoot, executionId);
170
+ const checkpoint = await loadCheckpointForMutation(executionId, paths, "unpin");
171
+ let found = false;
172
+ const next = {
173
+ decisions: checkpoint.decisions,
174
+ constraints: checkpoint.constraints,
175
+ openItems: checkpoint.openItems,
176
+ nextActions: checkpoint.nextActions,
177
+ };
178
+ for (const field of Object.keys(next)) {
179
+ const filtered = checkpoint[field].filter((pin) => pin.id !== pinId);
180
+ if (filtered.length !== checkpoint[field].length)
181
+ found = true;
182
+ next[field] = filtered;
183
+ }
184
+ // Checked before any write: an unknown ID must leave the checkpoint byte-for-byte as it was.
185
+ if (!found)
186
+ throw new Error(`no pin with ID \`${pinId}\``);
187
+ const now = (dependencies.now ?? (() => new Date().toISOString()))();
188
+ await persistCheckpoint(paths, { ...checkpoint, ...next, updatedAt: now });
189
+ dependencies.write(`UNPINNED ${pinId}\n`);
190
+ return 0;
191
+ }
192
+ async function runContextCommand(argv, dependencies) {
193
+ const [sub, ...rest] = argv;
194
+ if (sub === "status")
195
+ return commandStatus(rest, dependencies);
196
+ if (sub === "validate")
197
+ return commandValidate(rest, dependencies);
198
+ if (sub === "pin")
199
+ return commandPin(rest, dependencies);
200
+ if (sub === "unpin")
201
+ return commandUnpin(rest, dependencies);
202
+ throw new Error(USAGE);
203
+ }