cli-aimlock 1.0.2 → 5.0.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/README.md CHANGED
@@ -5,7 +5,7 @@ Aimlock — 智能目标 skill(CLI.Tax 发布)。
5
5
  - 把需求锁成可执行目标,阻止思考漂移、执行漂移、范围膨胀
6
6
  - Lock / Probe / Swarm 三档:小改不调蜂群;大改才派单
7
7
  - 改前文件快照,禁止创建 git 分支
8
- - 按目标调用 Blueprint、Swarm、Calctool;需要出图时调用 Image,让智能体生成图片
8
+ - 按目标调用 Blueprint、Swarm、Calctool;需要出图时调用 Images(`npx cli-images@latest install`,禁止安装 `cli-image`)
9
9
 
10
10
  安装:`npx cli-aimlock@latest install`
11
11
 
package/cli.mjs CHANGED
@@ -1,16 +1,7 @@
1
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'
2
+ import { dirname } from 'node:path'
6
3
  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'
4
+ import { dispatchOfficialSkillCli, runIntakeHandshake } from './installer.mjs'
14
5
 
15
6
  const INTAKE_QUESTIONS = [
16
7
  { id: 'goal', required: true, prompt: 'What must be true when this finishes, and what must never change?', example: '只改税率常量一行,不改其它计税逻辑' },
@@ -22,164 +13,14 @@ const INTAKE_QUESTIONS = [
22
13
  { id: 'deliveryDoc', required: true, prompt: 'After success, summarize a local delivery document? yes or no.', example: 'no' },
23
14
  ]
24
15
 
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
- }
16
+ await dispatchOfficialSkillCli({
17
+ packageRoot: dirname(fileURLToPath(import.meta.url)),
18
+ runCommand: (context) => runIntakeHandshake(context, {
19
+ questions: INTAKE_QUESTIONS,
20
+ outputFile: 'AIMLOCK-REQUIREMENTS.json',
21
+ afterCapabilities(output) {
22
+ const notice = output.firstUseNotice?.zh
23
+ if (typeof notice === 'string' && notice.trim()) console.log(notice)
24
+ },
25
+ }),
26
+ })
package/installer.mjs ADDED
@@ -0,0 +1,251 @@
1
+ /**
2
+ * 五个官方技能共用这一份安装器。packages/*/installer.mjs 必须与本文件字节一致。
3
+ * 禁止第二套超时、第二套版本来源、第二套 bin 名。
4
+ */
5
+ import { copyFile, mkdir, writeFile } from 'node:fs/promises'
6
+ import { existsSync, readFileSync } from 'node:fs'
7
+ import { dirname, join, resolve } from 'node:path'
8
+ import { stdin, stdout } from 'node:process'
9
+ import { createInterface } from 'node:readline/promises'
10
+ import { fileURLToPath } from 'node:url'
11
+
12
+ export const LOOKUP_TIMEOUT_MS = 8000
13
+ export const CALL_TIMEOUT_MS = 120_000
14
+ const INSTALL_META = 'install-meta.json'
15
+
16
+ function asObject(value, label) {
17
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
18
+ throw new Error(`${label} must be an object`)
19
+ }
20
+ return value
21
+ }
22
+
23
+ function requiredString(value, label) {
24
+ const text = typeof value === 'string' ? value.trim() : ''
25
+ if (!text) throw new Error(`${label} is required`)
26
+ return text
27
+ }
28
+
29
+ export function loadOfficialSkillContext(packageRoot) {
30
+ const pkg = asObject(JSON.parse(readFileSync(join(packageRoot, 'package.json'), 'utf8')), 'package.json')
31
+ const skill = asObject(JSON.parse(readFileSync(join(packageRoot, 'skill/skill.json'), 'utf8')), 'skill.json')
32
+ const npmName = requiredString(pkg.name, 'package.json name')
33
+ const packageVersion = requiredString(pkg.version, 'package.json version')
34
+ const displayName = requiredString(skill.displayName, 'skill.json displayName')
35
+ const skillName = requiredString(skill.name, 'skill.json name')
36
+ const schemaVersion = requiredString(skill.schemaVersion, 'skill.json schemaVersion')
37
+ const endpoint = requiredString(skill.endpoint, 'skill.json endpoint')
38
+ const skillVersion = requiredString(skill.version, 'skill.json version')
39
+ const runtimeCode = requiredString(endpoint.replace(/^https:\/\/cli\.tax\//, ''), 'runtime code')
40
+ if (!/^[A-Za-z0-9]{10}$/.test(runtimeCode)) {
41
+ throw new Error(`skill.json endpoint must be https://cli.tax/{10-char-code}: ${endpoint}`)
42
+ }
43
+ if (skillVersion.replace(/^v/i, '') !== packageVersion.replace(/^v/i, '')) {
44
+ throw new Error(`skill.json ${skillVersion} must match package.json ${packageVersion}`)
45
+ }
46
+ return {
47
+ packageRoot,
48
+ npmName,
49
+ packageVersion,
50
+ displayName,
51
+ skillName,
52
+ schemaVersion,
53
+ endpoint,
54
+ skillVersion,
55
+ runtimeCode,
56
+ latestEndpoint: `https://cli.tax/api/public/skills/${runtimeCode}`,
57
+ skillDir: join(packageRoot, 'skill'),
58
+ }
59
+ }
60
+
61
+ export function readInstallMeta(target) {
62
+ const path = join(target, INSTALL_META)
63
+ if (!existsSync(path)) return null
64
+ return asObject(JSON.parse(readFileSync(path, 'utf8')), INSTALL_META)
65
+ }
66
+
67
+ export function installTarget(skillName, explicit) {
68
+ if (explicit) return resolve(explicit)
69
+ const codexHome = process.env.CODEX_HOME?.trim()
70
+ if (codexHome) return join(codexHome, 'skills', skillName)
71
+ return join(process.cwd(), '.codex', 'skills', skillName)
72
+ }
73
+
74
+ export async function fetchLatestVersion(context) {
75
+ const response = await fetch(context.latestEndpoint, { signal: AbortSignal.timeout(LOOKUP_TIMEOUT_MS) })
76
+ if (!response.ok) throw new Error(`cli.tax skill lookup failed: HTTP ${response.status}`)
77
+ const data = asObject(await response.json(), 'cli.tax skill lookup')
78
+ return {
79
+ version: requiredString(data.version, 'cli.tax skill lookup version'),
80
+ displayName: requiredString(data.displayName, 'cli.tax skill lookup displayName'),
81
+ }
82
+ }
83
+
84
+ export async function callOfficialSkill(context, operation, input) {
85
+ const requestId = `${context.npmName}-${Date.now()}`
86
+ const response = await fetch(context.endpoint, {
87
+ method: 'POST',
88
+ headers: { 'Content-Type': 'application/json' },
89
+ body: JSON.stringify({
90
+ input: {
91
+ schemaVersion: context.schemaVersion,
92
+ requestId,
93
+ operation,
94
+ input,
95
+ },
96
+ }),
97
+ signal: AbortSignal.timeout(CALL_TIMEOUT_MS),
98
+ })
99
+ let payload
100
+ try {
101
+ payload = await response.json()
102
+ } catch {
103
+ throw new Error(`${context.displayName} ${operation} failed: non-JSON response (HTTP ${response.status}). Check ${context.endpoint}.`)
104
+ }
105
+ if (!response.ok || payload?.ok !== true) {
106
+ const message = payload?.error?.message
107
+ if (typeof message !== 'string' || !message.trim()) {
108
+ throw new Error(`${context.displayName} ${operation} failed: HTTP ${response.status}`)
109
+ }
110
+ throw new Error(`${context.displayName} ${operation} failed: ${message}`)
111
+ }
112
+ return payload
113
+ }
114
+
115
+ export async function installOfficialSkill(context, explicit) {
116
+ const target = installTarget(context.skillName, explicit)
117
+ await mkdir(target, { recursive: true })
118
+ const previous = readInstallMeta(target)
119
+ await copyFile(join(context.skillDir, 'SKILL.md'), join(target, 'SKILL.md'))
120
+ await copyFile(join(context.skillDir, 'skill.json'), join(target, 'skill.json'))
121
+ const installed = asObject(JSON.parse(readFileSync(join(target, 'skill.json'), 'utf8')), 'installed skill.json')
122
+ const installedVersion = requiredString(installed.version, 'installed skill.json version')
123
+ await writeFile(join(target, INSTALL_META), `${JSON.stringify({
124
+ source: context.runtimeCode,
125
+ slug: context.skillName,
126
+ version: installedVersion,
127
+ packageVersion: context.packageVersion,
128
+ endpoint: context.endpoint,
129
+ installedAt: new Date().toISOString(),
130
+ }, null, 2)}\n`)
131
+ if (previous?.version && previous.version !== installedVersion) {
132
+ console.log(`${context.displayName} skill updated: ${target}`)
133
+ console.log(` ${previous.version} → ${installedVersion}`)
134
+ } else {
135
+ console.log(`${context.displayName} skill installed: ${target} (${installedVersion})`)
136
+ }
137
+ if (context.npmName === 'cli-images') {
138
+ console.log('npm package: cli-images. Never install cli-image (third-party terminal viewer, not CLI.Tax).')
139
+ }
140
+ console.log('Next: return to your IDE and state the goal. The agent reads the installed SKILL.md.')
141
+ }
142
+
143
+ export async function checkOfficialSkill(context, explicit) {
144
+ const target = installTarget(context.skillName, explicit)
145
+ const current = readInstallMeta(target)
146
+ if (!current) {
147
+ console.log(`${context.displayName} skill is not installed. Run: npx ${context.npmName}@latest install`)
148
+ process.exitCode = 1
149
+ return
150
+ }
151
+ const installedVersion = requiredString(current.version, 'install-meta.json version')
152
+ const packageVersion = requiredString(current.packageVersion, 'install-meta.json packageVersion')
153
+ console.log(`Installed: ${installedVersion} (package ${packageVersion})`)
154
+ const latest = await fetchLatestVersion(context)
155
+ console.log(`Latest on cli.tax: ${latest.version}`)
156
+ if (installedVersion === latest.version) {
157
+ console.log('Up to date.')
158
+ return
159
+ }
160
+ console.log(`Update available: ${installedVersion} → ${latest.version}`)
161
+ console.log(`Run: npx ${context.npmName}@latest install`)
162
+ process.exitCode = 1
163
+ }
164
+
165
+ export function defaultUsage(context, extraLines) {
166
+ const lines = [
167
+ `${context.npmName} — install and run the ${context.displayName} skill from CLI.Tax`,
168
+ '',
169
+ 'Usage:',
170
+ ` npx ${context.npmName}@latest install [directory]`,
171
+ ` Install the ${context.displayName} skill for the current IDE.`,
172
+ ` npx ${context.npmName}@latest check [directory]`,
173
+ ' Check whether the installed skill has a newer version.',
174
+ ` npx ${context.npmName}@latest run`,
175
+ ' Run the skill handshake: discover capabilities and collect intake answers.',
176
+ '',
177
+ `Endpoint: ${context.endpoint}`,
178
+ ]
179
+ if (context.npmName === 'cli-images') {
180
+ lines.push(
181
+ '',
182
+ 'The npm package name is cli-images (plural).',
183
+ 'Never install cli-image: that is a third-party terminal image viewer, not CLI.Tax.',
184
+ )
185
+ }
186
+ if (extraLines?.length) lines.push('', ...extraLines)
187
+ return lines.join('\n')
188
+ }
189
+
190
+ export async function runIntakeHandshake(context, spec) {
191
+ const capabilities = await callOfficialSkill(context, 'capabilities', {})
192
+ const output = capabilities.output && typeof capabilities.output === 'object' ? capabilities.output : {}
193
+ const skill = output.skill && typeof output.skill === 'object' ? output.skill : {}
194
+ const version = typeof skill.version === 'string' && skill.version.trim()
195
+ ? skill.version.trim()
196
+ : context.skillVersion
197
+ console.log(`${context.displayName} ${version}`)
198
+ if (typeof spec.afterCapabilities === 'function') spec.afterCapabilities(output)
199
+ const readline = createInterface({ input: stdin, output: stdout })
200
+ const answers = []
201
+ try {
202
+ for (const question of spec.questions) {
203
+ const requiredMark = question.required ? ' (required)' : ''
204
+ console.log(`\n${question.prompt}${requiredMark}`)
205
+ console.log(`Example: ${question.example}`)
206
+ for (;;) {
207
+ const answer = (await readline.question('> ')).trim()
208
+ if (answer) {
209
+ answers.push({ id: question.id, prompt: question.prompt, answer })
210
+ break
211
+ }
212
+ if (!question.required) break
213
+ console.log('This question is required. Please answer before continuing.')
214
+ }
215
+ }
216
+ } finally {
217
+ readline.close()
218
+ }
219
+ const target = join(process.cwd(), spec.outputFile)
220
+ await writeFile(target, `${JSON.stringify({
221
+ schemaVersion: context.schemaVersion,
222
+ endpoint: context.endpoint,
223
+ createdAt: new Date().toISOString(),
224
+ answers,
225
+ }, null, 2)}\n`)
226
+ console.log(`\nRequirements saved: ${target}`)
227
+ console.log('Next: continue in your IDE agent with this file.')
228
+ }
229
+
230
+ export async function dispatchOfficialSkillCli(options) {
231
+ const packageRoot = options.packageRoot ?? dirname(fileURLToPath(options.importMetaUrl))
232
+ const context = loadOfficialSkillContext(packageRoot)
233
+ const args = process.argv.slice(2)
234
+ const command = args[0] ?? 'help'
235
+ const argument = args[1]
236
+ try {
237
+ if (command === 'install') await installOfficialSkill(context, argument)
238
+ else if (command === 'check') await checkOfficialSkill(context, argument)
239
+ else if (command === 'run') await options.runCommand(context)
240
+ else if (command === 'help' || command === '--help' || command === '-h') {
241
+ console.log(options.usage ? options.usage(context) : defaultUsage(context, options.extraUsageLines))
242
+ } else {
243
+ console.error(`Unknown command: ${command}`)
244
+ console.log(options.usage ? options.usage(context) : defaultUsage(context, options.extraUsageLines))
245
+ process.exitCode = 1
246
+ }
247
+ } catch (error) {
248
+ console.error(error instanceof Error ? error.message : error)
249
+ process.exitCode = 1
250
+ }
251
+ }
package/package.json CHANGED
@@ -1,29 +1,22 @@
1
1
  {
2
- "name": "cli-aimlock",
3
- "version": "1.0.2",
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
2
  "bin": {
7
3
  "cli-aimlock": "./cli.mjs"
8
4
  },
5
+ "description": "Aimlock skill installer for CLI.Tax: lock a user request into an executable aim and route Blueprint, Swarm, Calctool, and Images.",
9
6
  "files": [
10
7
  "cli.mjs",
8
+ "installer.mjs",
11
9
  "README.md",
12
10
  "skill/SKILL.md",
13
11
  "skill/skill.json"
14
12
  ],
15
- "engines": {
16
- "node": ">=18"
17
- },
13
+ "license": "UNLICENSED",
14
+ "name": "cli-aimlock",
15
+ "private": false,
18
16
  "repository": {
19
17
  "type": "git",
20
18
  "url": "https://github.com/88208555/aimlock-clitax.git"
21
19
  },
22
- "license": "UNLICENSED",
23
- "keywords": [
24
- "cli.tax",
25
- "skill",
26
- "installer",
27
- "agent"
28
- ]
20
+ "type": "module",
21
+ "version": "5.0.0"
29
22
  }
package/skill/SKILL.md CHANGED
@@ -1,6 +1,6 @@
1
1
  ---
2
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."
3
+ description: "Aimlock 把用户需求锁成可执行的智能目标,阻止思考漂移、执行漂移和范围膨胀。主智能体先读本规范,禁止立刻改代码:先拆 JSON 任务,按范围合同分成 Lock / Probe / Swarm。Lock 档单文件小改由主脑快照后改写;Probe 档只读分析修改节点,确认后再写;Swarm 档才调用蜂群。Blueprint 编规划合同,Swarm 派单执行,Calctool 生成计算工具,Images 让智能体生成图片。改前文件快照,禁止创建 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, Images 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 — калькулятор, Images — генерация картинок агентом. Снимок файлов до правки, без git-веток. Сначала capabilities."
4
4
  ---
5
5
 
6
6
  # Aimlock Skill
@@ -9,7 +9,7 @@ Endpoint: https://cli.tax/R3mQ8kWpXn
9
9
  Request schema: aimlock.skill.request/1.0
10
10
  Response schema: aimlock.skill.response/1.0
11
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**.
12
+ Aimlock is a policy layer. It does not replace Blueprint, Swarm, or Calctool. Images 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
13
 
14
14
  ## Request envelope
15
15
 
@@ -33,7 +33,7 @@ POST JSON to the endpoint with an `input` wrapper:
33
33
  - `intake`: questions the IDE must ask before classify. One at a time.
34
34
  - `classify`: choose `lock` | `probe` | `swarm` from explicit facts. Missing facts → `blocked`.
35
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.
36
+ - `skill-route`: whether to call Blueprint, Swarm, Calctool; call Images only so the agent can generate pictures.
37
37
  - `propose-nodes`: validate read-only modification nodes against the contract.
38
38
  - `accept-nodes`: auto-accept in-scope nodes; escalate worker conflicts.
39
39
  - `snapshot-plan`: file-copy snapshot. Git branches and worktrees are forbidden.
@@ -77,7 +77,7 @@ Call a hop only when `call` is true. That means the hop's capability matches thi
77
77
  - Do not call self-extended or marketplace extras.
78
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
79
 
80
- Do not call Image for ordinary code edits. Do not call Calctool unless the aim is a calculator tool.
80
+ Do not call Images for ordinary code edits. Do not call Calctool unless the aim is a calculator tool. Images npm package is `cli-images`. Quick start: `npx cli-images@latest install`. Never install `cli-image`: that is a third-party terminal image viewer, unrelated to CLI.Tax.
81
81
 
82
82
  ### Interrupt
83
83
 
@@ -120,8 +120,8 @@ User: 修支付回调的状态机,可能有上下游.
120
120
 
121
121
  `classify` → `probe`. Worker returns nodes. If a node points outside `allowedPaths`, `propose-nodes` is `blocked`. After accept + snapshot, mutate.
122
122
 
123
- ### Image capability
123
+ ### Images capability
124
124
 
125
125
  User: 根据这个商品说明生成三张主图.
126
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.
127
+ `goalKind`: `image`. `skill-route` returns Images with `call: true`. The agent uses the Images skill to generate pictures. Install Images with `npx cli-images@latest install`. Never install `cli-image`. Aimlock still owns the aim, keep-alive, and interrupt rules.
package/skill/skill.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
- "name": "aimlock",
2
+ "description": "Aimlock 把用户需求锁成可执行的智能目标,专门阻止思考漂移、执行漂移和范围膨胀。主智能体载入本技能后禁止立刻改代码,必须先把需求拆成 JSON 任务,并用范围合同分成 Lock、Probe、Swarm 三档。Lock 只覆盖单文件且变更预算明确的小改,主脑快照后改写并对账。Probe 先只读分析修改节点与上下游,确认一致后再写。Swarm 才调用蜂群派单认领。规划合同交给 Blueprint,计算工具交给 Calctool,需要出图时交给 Images 让智能体生成图片,执行编排交给 Swarm;Aimlock 只负责瞄准、闸门、插话融合与无分支快照。每次改前必须备份目标文件,禁止创建 git 分支,禁止用 worktree 冒充隔离。用户中途插入新需求时,主脑先判断是否与在跑任务关联:无关则另派临时智能体,有关则发信号更新 JSON 后继续;用户强制停止则立即停止。IDE 在目标未完成并即将交出控制权时,按九十秒间隔发送固定文案「智能目标持续执行中,请勿关闭!」。交付文档不是默认产物,必须由用户确认后才汇总。调用顺序为 capabilities、intake、classify、scope-contract:缺必填项不得进入下一操作。密钥与凭据不得写入公开页面或任务 JSON。本技能面向真实交付:每一步都有输入、规则与失败面,禁止把加载中、超时或未知状态当成空成功。用户可见说明只讲能力与对话配置方式,不出现外链。调用前必须先走 capabilities,再按 nextStep 前进;必填项未回答不得进入下一操作。日志只保存必要元数据,密钥不得写入公开页面。",
3
3
  "displayName": "Aimlock",
4
- "description": "智能目标:把需求锁成可执行目标,按 Lock / Probe / Swarm 分档,先分析再改代码,文件快照禁止 git 分支;可调用 Blueprint、Swarm、Calctool,以及 Image 让智能体生成图片。",
5
- "schemaVersion": "aimlock.skill.request/1.0",
6
4
  "endpoint": "https://cli.tax/R3mQ8kWpXn",
7
5
  "method": "POST",
8
- "version": "v1.0.1",
9
- "type": "Skill"
6
+ "name": "aimlock",
7
+ "schemaVersion": "aimlock.skill.request/1.0",
8
+ "type": "Skill",
9
+ "version": "v5.0.0"
10
10
  }