cli-aimlock 1.0.1

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/README.md ADDED
@@ -0,0 +1,10 @@
1
+ # cli-aimlock
2
+
3
+ Aimlock — 智能目标 skill(CLI.Tax 发布)。
4
+
5
+ - 把需求锁成可执行目标,阻止思考漂移、执行漂移、范围膨胀
6
+ - Lock / Probe / Swarm 三档:小改不调蜂群;大改才派单
7
+ - 改前文件快照,禁止创建 git 分支
8
+ - 按目标调用 Blueprint、Swarm、Calctool;需要出图时调用 Image,让智能体生成图片
9
+
10
+ 安装:`npx cli-aimlock@latest install`
package/cli.mjs ADDED
@@ -0,0 +1,185 @@
1
+ #!/usr/bin/env node
2
+ import { copyFile, mkdir, writeFile } from 'node:fs/promises'
3
+ import { createInterface } from 'node:readline/promises'
4
+ import { stdin, stdout } from 'node:process'
5
+ import { dirname, join, resolve } from 'node:path'
6
+ import { fileURLToPath } from 'node:url'
7
+ import { existsSync, readFileSync } from 'node:fs'
8
+
9
+ const ENDPOINT = 'https://cli.tax/R3mQ8kWpXn'
10
+ const SCHEMA_VERSION = 'aimlock.skill.request/1.0'
11
+ const PACKAGE_SKILL_DIR = join(dirname(fileURLToPath(import.meta.url)), 'skill')
12
+ const INSTALL_META = 'install-meta.json'
13
+ const LATEST_ENDPOINT = 'https://cli.tax/api/public/skills/R3mQ8kWpXn'
14
+
15
+ const INTAKE_QUESTIONS = [
16
+ { id: 'goal', required: true, prompt: 'What must be true when this finishes, and what must never change?', example: '只改税率常量一行,不改其它计税逻辑' },
17
+ { id: 'targetFiles', required: true, prompt: 'Which file paths are in scope? Use unknown if not located yet.', example: 'apps/web/src/tax.ts' },
18
+ { id: 'estimatedChangedLines', required: true, prompt: 'How many lines should change?', example: '1' },
19
+ { id: 'crossModule', required: true, prompt: 'Does this cross modules? yes or no.', example: 'no' },
20
+ { id: 'needParallel', required: true, prompt: 'Must independent modules run in parallel? yes or no.', example: 'no' },
21
+ { id: 'goalKind', required: true, prompt: 'Goal kind: code, calculator, image, mixed, or docs.', example: 'code' },
22
+ { id: 'deliveryDoc', required: true, prompt: 'After success, summarize a local delivery document? yes or no.', example: 'no' },
23
+ ]
24
+
25
+ function usage() {
26
+ return [
27
+ 'cli-aimlock — install and run the Aimlock skill from CLI.Tax',
28
+ '',
29
+ 'Usage:',
30
+ ' npx cli-aimlock@latest install [directory]',
31
+ ' Install Aimlock for the current IDE (Codex skills directory by default).',
32
+ ' npx cli-aimlock@latest check [directory]',
33
+ ' Check whether the installed skill has a newer version on cli.tax.',
34
+ ' npx cli-aimlock@latest run',
35
+ ' Handshake: capabilities, intake questions, save AIMLOCK-REQUIREMENTS.json.',
36
+ '',
37
+ `Endpoint: ${ENDPOINT}`,
38
+ ].join('\n')
39
+ }
40
+
41
+ function readMeta(dir) {
42
+ const path = join(dir, INSTALL_META)
43
+ if (!existsSync(path)) return null
44
+ try { return JSON.parse(readFileSync(path, 'utf8')) } catch { return null }
45
+ }
46
+
47
+ async function fetchLatestVersion() {
48
+ try {
49
+ const response = await fetch(LATEST_ENDPOINT)
50
+ if (!response.ok) return null
51
+ const data = await response.json()
52
+ return { version: data.version ?? '', displayName: data.displayName ?? 'aimlock' }
53
+ } catch {
54
+ return null
55
+ }
56
+ }
57
+
58
+ async function postRequest(operation, requestId) {
59
+ const response = await fetch(ENDPOINT, {
60
+ method: 'POST',
61
+ headers: { 'Content-Type': 'application/json' },
62
+ body: JSON.stringify({
63
+ input: { schemaVersion: SCHEMA_VERSION, requestId, operation, input: {} },
64
+ }),
65
+ })
66
+ let payload
67
+ try {
68
+ payload = await response.json()
69
+ } catch {
70
+ throw new Error(`aimlock ${operation} failed: non-JSON response (HTTP ${response.status}). Check ${ENDPOINT}.`)
71
+ }
72
+ if (!response.ok || payload?.ok !== true) {
73
+ const message = payload?.error?.message ?? payload?.error ?? `HTTP ${response.status}`
74
+ throw new Error(`aimlock ${operation} failed: ${message}`)
75
+ }
76
+ return payload
77
+ }
78
+
79
+ function installTarget(explicit) {
80
+ if (explicit) return resolve(explicit)
81
+ const codexHome = process.env.CODEX_HOME?.trim()
82
+ if (codexHome) return join(codexHome, 'skills', 'aimlock')
83
+ return join(process.cwd(), '.codex', 'skills', 'aimlock')
84
+ }
85
+
86
+ async function install(explicit) {
87
+ const target = installTarget(explicit)
88
+ await mkdir(target, { recursive: true })
89
+ const previous = readMeta(target)
90
+ await copyFile(join(PACKAGE_SKILL_DIR, 'SKILL.md'), join(target, 'SKILL.md'))
91
+ await copyFile(join(PACKAGE_SKILL_DIR, 'skill.json'), join(target, 'skill.json'))
92
+ const latest = await fetchLatestVersion()
93
+ await writeFile(join(target, INSTALL_META), `${JSON.stringify({
94
+ source: 'R3mQ8kWpXn',
95
+ slug: 'aimlock',
96
+ version: latest?.version ?? '',
97
+ endpoint: ENDPOINT,
98
+ installedAt: new Date().toISOString(),
99
+ }, null, 2)}\n`)
100
+ if (previous?.version && latest?.version && previous.version !== latest.version) {
101
+ console.log(`aimlock skill updated: ${target}`)
102
+ console.log(` ⤴ ${previous.version} → ${latest.version}`)
103
+ } else {
104
+ console.log(`aimlock skill installed: ${target}${latest?.version ? ` (${latest.version})` : ''}`)
105
+ }
106
+ if (latest?.version) console.log(`Latest version on cli.tax: ${latest.version}`)
107
+ console.log('Next: return to your IDE and describe the aim. Do not edit code until Aimlock classifies and gates mutate.')
108
+ }
109
+
110
+ async function check(explicit) {
111
+ const target = installTarget(explicit)
112
+ const local = readMeta(target)
113
+ const latest = await fetchLatestVersion()
114
+ if (!latest) {
115
+ console.log('aimlock: cannot reach cli.tax to check updates.')
116
+ process.exitCode = 1
117
+ return
118
+ }
119
+ if (!local?.version) {
120
+ console.log(`aimlock: no version record in ${target}. Latest on cli.tax: ${latest.version}.`)
121
+ process.exitCode = 1
122
+ return
123
+ }
124
+ if (local.version === latest.version) {
125
+ console.log(`aimlock is up to date (${latest.version}) at ${target}`)
126
+ return
127
+ }
128
+ console.log(`aimlock update available: ${local.version} → ${latest.version}`)
129
+ console.log('Run: npx cli-aimlock@latest install')
130
+ process.exitCode = 1
131
+ }
132
+
133
+ async function askOne(question, readline) {
134
+ const requiredMark = question.required ? ' (required)' : ''
135
+ console.log(`\n${question.prompt}${requiredMark}`)
136
+ console.log(`Example: ${question.example}`)
137
+ for (;;) {
138
+ const answer = (await readline.question('> ')).trim()
139
+ if (answer || !question.required) return answer || ''
140
+ console.log('This question is required. Please answer before continuing.')
141
+ }
142
+ }
143
+
144
+ async function run() {
145
+ const capabilities = await postRequest('capabilities', 'cli-1')
146
+ const skill = capabilities.output?.skill ?? {}
147
+ const notice = capabilities.output?.firstUseNotice?.zh
148
+ console.log(`aimlock ${skill.version ?? ''} — lock the aim, then fire`)
149
+ if (notice) console.log(notice)
150
+ const readline = createInterface({ input: stdin, output: stdout })
151
+ const answers = []
152
+ try {
153
+ for (const question of INTAKE_QUESTIONS) {
154
+ answers.push({ id: question.id, prompt: question.prompt, answer: await askOne(question, readline) })
155
+ }
156
+ } finally {
157
+ readline.close()
158
+ }
159
+ const target = join(process.cwd(), 'AIMLOCK-REQUIREMENTS.json')
160
+ await writeFile(target, `${JSON.stringify({
161
+ schemaVersion: SCHEMA_VERSION,
162
+ endpoint: ENDPOINT,
163
+ createdAt: new Date().toISOString(),
164
+ answers,
165
+ }, null, 2)}\n`)
166
+ console.log(`\nRequirements saved: ${target}`)
167
+ console.log('Next: continue in your IDE agent with this file. Do not mutate until classify + mutate-gate.')
168
+ }
169
+
170
+ const command = process.argv[2] ?? 'help'
171
+ const argument = process.argv[3] ?? ''
172
+ try {
173
+ if (command === 'install') await install(argument)
174
+ else if (command === 'check') await check(argument)
175
+ else if (command === 'run') await run()
176
+ else if (command === '--help' || command === '-h' || command === 'help') console.log(usage())
177
+ else {
178
+ console.error(`Unknown command: ${command}\n`)
179
+ console.log(usage())
180
+ process.exitCode = 1
181
+ }
182
+ } catch (error) {
183
+ console.error(error instanceof Error ? error.message : error)
184
+ process.exitCode = 1
185
+ }
package/package.json ADDED
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "cli-aimlock",
3
+ "version": "1.0.1",
4
+ "description": "Aimlock skill installer for CLI.Tax: lock a user request into an executable aim and route Blueprint, Swarm, Calctool, and Image.",
5
+ "type": "module",
6
+ "bin": {
7
+ "cli-aimlock": "./cli.mjs"
8
+ },
9
+ "files": [
10
+ "cli.mjs",
11
+ "README.md",
12
+ "skill/SKILL.md",
13
+ "skill/skill.json"
14
+ ],
15
+ "engines": {
16
+ "node": ">=18"
17
+ },
18
+ "license": "UNLICENSED",
19
+ "keywords": [
20
+ "cli.tax",
21
+ "skill",
22
+ "installer",
23
+ "agent"
24
+ ]
25
+ }
package/skill/SKILL.md ADDED
@@ -0,0 +1,127 @@
1
+ ---
2
+ name: aimlock
3
+ description: "Aimlock 把用户需求锁成可执行的智能目标,阻止思考漂移、执行漂移和范围膨胀。主智能体先读本规范,禁止立刻改代码:先拆 JSON 任务,按范围合同分成 Lock / Probe / Swarm。Lock 档单文件小改由主脑快照后改写;Probe 档只读分析修改节点,确认后再写;Swarm 档才调用蜂群。Blueprint 编规划合同,Swarm 派单执行,Calctool 生成计算工具,Image 让智能体生成图片。改前文件快照,禁止创建 git 分支。插话先判关联再更新任务;强制停止立即停止。目标未完成交出控制权时每 90 秒发送「智能目标持续执行中,请勿关闭!」。交付文档需用户确认。调用前必须 capabilities,再按 nextStep 前进。Locks a user request into an executable aim to stop thought-drift, execution-drift, and scope blow-ups. Read this skill first; do not edit code yet. Split JSON tasks; classify Lock / Probe / Swarm. Blueprint for contracts, Swarm for dispatch, Calctool for calculators, Image so the agent can generate pictures. Snapshot files before mutate; never create git branches. Interrupt: correlate first. Keep-alive every 90s while the aim is open. Delivery docs only if the user confirms. Always call capabilities first. Фиксирует запрос в исполняемую цель, чтобы остановить дрейф мысли, дрейф исполнения и раздувание объёма. Сначала эта спецификация, код не трогать. JSON-задачи, режимы Lock / Probe / Swarm. Blueprint — контракт, Swarm — раздача, Calctool — калькулятор, Image — генерация картинок агентом. Снимок файлов до правки, без git-веток. Сначала capabilities."
4
+ ---
5
+
6
+ # Aimlock Skill
7
+
8
+ Endpoint: https://cli.tax/R3mQ8kWpXn
9
+ Request schema: aimlock.skill.request/1.0
10
+ Response schema: aimlock.skill.response/1.0
11
+
12
+ Aimlock is a policy layer. It does not replace Blueprint, Swarm, or Calctool. Image is a **capability** the agent uses to generate pictures, not a product line. Aimlock decides **when to fire, how wide, and how to stop drift**.
13
+
14
+ ## Request envelope
15
+
16
+ POST JSON to the endpoint with an `input` wrapper:
17
+
18
+ ```json
19
+ {
20
+ "input": {
21
+ "schemaVersion": "aimlock.skill.request/1.0",
22
+ "requestId": "<unique-id>",
23
+ "operation": "<operation>",
24
+ "input": {}
25
+ }
26
+ }
27
+ ```
28
+
29
+ ## Operations
30
+
31
+ - `capabilities`: modes, sibling skills, keep-alive text, first-use notice.
32
+ - `help`: operation catalog.
33
+ - `intake`: questions the IDE must ask before classify. One at a time.
34
+ - `classify`: choose `lock` | `probe` | `swarm` from explicit facts. Missing facts → `blocked`.
35
+ - `scope-contract`: allowed paths, forbidden paths, max changed lines, new-file / delete flags.
36
+ - `skill-route`: whether to call Blueprint, Swarm, Calctool; call Image only so the agent can generate pictures.
37
+ - `propose-nodes`: validate read-only modification nodes against the contract.
38
+ - `accept-nodes`: auto-accept in-scope nodes; escalate worker conflicts.
39
+ - `snapshot-plan`: file-copy snapshot. Git branches and worktrees are forbidden.
40
+ - `mutate-gate`: mutate only after accept + snapshot.
41
+ - `continuity-check`: traffic-light budget, tests, omission scan.
42
+ - `interrupt`: `status` | `fuse` | `spawn` | `stop`.
43
+ - `keep-alive`: arm a 90s ping while the goal is open.
44
+ - `delivery-doc`: write a summary only if the user confirmed.
45
+ - `validate-json`: validate an Aimlock run JSON.
46
+
47
+ ## Required flow
48
+
49
+ 1. Call `capabilities`. On first use in the conversation, show `firstUseNotice` once.
50
+ 2. Call `intake` and ask every **required** question one at a time. Do not mutate files.
51
+ 3. Call `classify` with the answers. Do not invent file lists or line budgets.
52
+ 4. Call `scope-contract`. Empty `allowedPaths` is `blocked`.
53
+ 5. Call `skill-route` with `mode`, `goalKind`, `hasBlueprint`.
54
+ 6. **Probe / Swarm:** workers read code only and return nodes. Call `propose-nodes` then `accept-nodes`.
55
+ 7. **Lock:** the main agent still snapshots, then mutates inside the contract. No swarm.
56
+ 8. Call `snapshot-plan`. Copy files into `snapshotRoot`. Never `git branch` / `git checkout -b` / worktree.
57
+ 9. Call `mutate-gate`. If `blocked`, do not write.
58
+ 10. After writes, call `continuity-check`. Red or yellow → roll back from the snapshot.
59
+ 11. Before yielding while the aim is open, call `keep-alive` with `goalComplete: false` and send the returned message.
60
+ 12. Reclaim temporary agents after green. Ask about `delivery-doc` only if intake said the user wants it.
61
+
62
+ ### Classify rules (deterministic)
63
+
64
+ Facts required: `goal`, `targetFiles` (string array), `estimatedChangedLines`, `crossModule`, `needParallel`.
65
+
66
+ - **lock**: exactly one file, ≤ 20 lines, not cross-module, not parallel.
67
+ - **probe**: ≤ 3 files, ≤ 80 lines, not parallel.
68
+ - **swarm**: otherwise.
69
+
70
+ ### Skill routing
71
+
72
+ Default allowlist is **official skills**. `capabilities` (platform) returns `officialCatalog`. Pass it into `skill-route` with `mode`, `goalKind`, `hasBlueprint`.
73
+
74
+ Call a hop only when `call` is true. That means the hop's capability matches this demand and the current chain allows it.
75
+
76
+ - Do not call chain-unrelated skills.
77
+ - Do not call self-extended or marketplace extras.
78
+ - Extra skills enter the candidate list only when the user names them (`userSpecifiedSkills`). Then call that skill's `capabilities` and invoke only if its capability matches the demand.
79
+
80
+ Do not call Image for ordinary code edits. Do not call Calctool unless the aim is a calculator tool.
81
+
82
+ ### Interrupt
83
+
84
+ Call `interrupt` with `forceStop`, `isStatusQuery`, `related` as booleans. Do not execute a new request first.
85
+
86
+ - `stop`: user forced stop.
87
+ - `status`: report only.
88
+ - `fuse`: related; signal the running agent; update JSON; continue.
89
+ - `spawn`: unrelated; new temporary agent; do not hijack the current aim.
90
+
91
+ ### Keep-alive
92
+
93
+ When the aim is incomplete and the IDE is about to yield, send exactly:
94
+
95
+ `智能目标持续执行中,请勿关闭!`
96
+
97
+ Interval: 90 seconds. Do not ping every 10 seconds. When `goalComplete` is true, do not arm.
98
+
99
+ ## Safety rules
100
+
101
+ - Never create a git branch. Isolation is a file-copy snapshot plus a temporary agent context.
102
+ - Never mutate before `mutate-gate` returns `allowed: true`.
103
+ - Never treat missing files, timeouts, or 4xx/5xx as empty success. `blocked` and `failed` are errors.
104
+ - Never send credentials in the envelope.
105
+ - The response `status` must be `succeeded`; `blocked` and `failed` are not results.
106
+ - Do not expand 1 line into 100. Over-budget is red; roll back.
107
+ - Delivery documents are optional. Skip unless the user confirmed.
108
+
109
+ ## Examples
110
+
111
+ ### Lock: one-line constant
112
+
113
+ User: 只改税率常量一行.
114
+
115
+ `classify` → `lock`. Snapshot that file. Change the one line. `continuity-check` must stay within `maxChangedLines`.
116
+
117
+ ### Probe then mutate
118
+
119
+ User: 修支付回调的状态机,可能有上下游.
120
+
121
+ `classify` → `probe`. Worker returns nodes. If a node points outside `allowedPaths`, `propose-nodes` is `blocked`. After accept + snapshot, mutate.
122
+
123
+ ### Image capability
124
+
125
+ User: 根据这个商品说明生成三张主图.
126
+
127
+ `goalKind`: `image`. `skill-route` returns Image with `call: true`. The agent uses the Image skill to generate pictures. Aimlock still owns the aim, keep-alive, and interrupt rules.
@@ -0,0 +1,10 @@
1
+ {
2
+ "name": "aimlock",
3
+ "displayName": "Aimlock",
4
+ "description": "智能目标:把需求锁成可执行目标,按 Lock / Probe / Swarm 分档,先分析再改代码,文件快照禁止 git 分支;可调用 Blueprint、Swarm、Calctool,以及 Image 让智能体生成图片。",
5
+ "schemaVersion": "aimlock.skill.request/1.0",
6
+ "endpoint": "https://cli.tax/R3mQ8kWpXn",
7
+ "method": "POST",
8
+ "version": "v1.0.1",
9
+ "type": "Skill"
10
+ }