@rover-studio/answer-me 0.1.0-rc.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/bin/answerme-toolkit.mjs +6 -0
- package/distribution/npm/migrations.json +605 -0
- package/distribution/npm/package-manifest.json +192 -0
- package/distribution/npm/skills/answerme/SKILL.md +94 -0
- package/distribution/npm/skills/answerme/agents/openai.yaml +4 -0
- package/distribution/npm/skills/answerme/references/api.md +135 -0
- package/distribution/npm/skills/answerme/references/creator-credential-deployment.md +19 -0
- package/distribution/npm/skills/answerme/references/creator-credential-recovery.md +24 -0
- package/distribution/npm/skills/answerme/references/errors.md +44 -0
- package/distribution/npm/skills/answerme/references/handoff.md +46 -0
- package/distribution/npm/skills/answerme/references/install-self-test.md +28 -0
- package/distribution/npm/skills/answerme/references/result-token-store.md +50 -0
- package/distribution/npm/skills/answerme/references/templates.md +139 -0
- package/distribution/npm/skills/answerme/scripts/answerme-api-base-url.ps1 +40 -0
- package/distribution/npm/skills/answerme/scripts/create-answerme.ps1 +1892 -0
- package/distribution/npm/skills/answerme/scripts/creator-credential-store.windows.ps1 +503 -0
- package/distribution/npm/skills/answerme/scripts/deploy-answerme-creator-credential.ps1 +447 -0
- package/distribution/npm/skills/answerme/scripts/enroll-answerme-creator.ps1 +764 -0
- package/distribution/npm/skills/answerme/scripts/open-answerme-page.windows.ps1 +272 -0
- package/distribution/npm/skills/answerme/scripts/remove-answerme-result-token.ps1 +63 -0
- package/distribution/npm/skills/answerme/scripts/result-token-store.windows.ps1 +261 -0
- package/distribution/npm/skills/answerme/scripts/test-answerme-installation.ps1 +498 -0
- package/distribution/npm/skills/answerme/scripts/wait-answerme-result.ps1 +908 -0
- package/distribution/npm/skills/answerme/scripts/windows-crypto.ps1 +57 -0
- package/distribution/npm/skills/answerme/scripts/windows-http.ps1 +45 -0
- package/distribution/npm/skills/answerme/scripts/windows-process-start-info.ps1 +76 -0
- package/distribution/npm/skills/ask-when-needed/SKILL.md +164 -0
- package/distribution/npm/skills/ask-when-needed/agents/openai.yaml +4 -0
- package/distribution/npm/skills/ask-when-needed/references/interview-strategies.md +43 -0
- package/lib/npm-cli/commands.mjs +247 -0
- package/lib/npm-cli/constants.mjs +51 -0
- package/lib/npm-cli/errors.mjs +15 -0
- package/lib/npm-cli/filesystem.mjs +193 -0
- package/lib/npm-cli/host-discovery.mjs +404 -0
- package/lib/npm-cli/main.mjs +42 -0
- package/lib/npm-cli/package-integrity.mjs +212 -0
- package/lib/npm-cli/transaction.mjs +375 -0
- package/lib/npm-cli/usage-validation.mjs +349 -0
- package/package.json +17 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Result Token Store 契约
|
|
2
|
+
|
|
3
|
+
## 目标
|
|
4
|
+
|
|
5
|
+
Result Token Store 为 AnswerMe 提供跨进程、跨任务的结果凭证恢复能力。核心 Skill 只依赖本契约,不依赖某个操作系统的加密 API。
|
|
6
|
+
|
|
7
|
+
## 必需操作
|
|
8
|
+
|
|
9
|
+
每个平台适配器必须提供以下行为:
|
|
10
|
+
|
|
11
|
+
| 操作 | 输入 | 结果 |
|
|
12
|
+
|---|---|---|
|
|
13
|
+
| `Validate` | 无,或受控测试根目录 | 验证当前身份能够加密、保存、回读并精确删除测试记录 |
|
|
14
|
+
| `Save` | `interactionId`、Result Token | 原子保存并回读验证;同一 Token 可幂等重放,不同 Token 必须冲突失败 |
|
|
15
|
+
| `Load` | `interactionId` | 仅向当前进程返回明文工作副本,不写入输出、日志或命令参数 |
|
|
16
|
+
| `Delete` | `interactionId` | 只删除该交互的精确记录;不存在时安全返回未删除 |
|
|
17
|
+
|
|
18
|
+
## 安全不变量
|
|
19
|
+
|
|
20
|
+
- Result Token 不得写入仓库、Skill、聊天、命令参数、普通日志、Trace 或明文文件。
|
|
21
|
+
- 进程内存和环境变量只能保存工作副本,不能作为唯一副本。
|
|
22
|
+
- 存储键必须由 `interactionId` 安全派生,不能把未校验输入直接拼入文件路径。
|
|
23
|
+
- `Save` 成功必须同时满足:持久化完成、当前身份回读成功、回读值与原值一致。
|
|
24
|
+
- `pending`、等待超时、断网、空结果、进程退出、任务中断和 Result API 404 均不得触发删除。
|
|
25
|
+
- 只有终态结果已经成功映射回原任务,或用户明确放弃恢复并授权删除时,才能调用 `Delete`。
|
|
26
|
+
- 缺少可用适配器、验证失败或保存失败时必须失败关闭;不得交付 Answer URL,也不得重复创建替代交互。
|
|
27
|
+
|
|
28
|
+
## 平台适配
|
|
29
|
+
|
|
30
|
+
| 平台 | 推荐实现 | 当前状态 |
|
|
31
|
+
|---|---|---|
|
|
32
|
+
| Windows | 当前 Windows 用户保护的 DPAPI 或系统凭证库 | 已提供 DPAPI adapter |
|
|
33
|
+
| macOS | Keychain | 未提供 adapter,必须失败关闭 |
|
|
34
|
+
| Linux 桌面 | Secret Service / libsecret | 未提供 adapter,必须失败关闭 |
|
|
35
|
+
| CI、容器、远程 Agent | 宿主 Secret Store 或 KMS | 未提供 adapter,必须失败关闭 |
|
|
36
|
+
|
|
37
|
+
适配器只解决本机或宿主范围内的任务恢复。跨主机恢复需要共享 Secret Store,或由 AnswerMe 服务提供独立的安全凭证恢复协议。
|
|
38
|
+
|
|
39
|
+
## Windows adapter
|
|
40
|
+
|
|
41
|
+
当前实现位于 `scripts/result-token-store.windows.ps1`:
|
|
42
|
+
|
|
43
|
+
- 默认目录:`%LOCALAPPDATA%\AnswerMe\result-token-credentials`;
|
|
44
|
+
- 使用当前 Windows 账号的 DPAPI 加密 `PSCredential`;
|
|
45
|
+
- 文件名使用 `SHA-256(interactionId)`,不直接使用外部输入;
|
|
46
|
+
- CLIXML 的 `UserName` 也只保存固定前缀与 `SHA-256(interactionId)`,不得明文保存原始 `interactionId`;
|
|
47
|
+
- 先写临时加密记录并回读验证,再原子移动到最终路径;
|
|
48
|
+
- 非默认目录只允许隔离测试显式开启。
|
|
49
|
+
|
|
50
|
+
`scripts/create-answerme.ps1` 在联网创建前验证 Store,创建成功后先持久化并回读,再返回不含 Result Token 的交付结果。`scripts/wait-answerme-result.ps1` 只从受保护 Store 恢复 Token;进程环境变量若存在,必须与受保护副本一致。完成终态结果映射后,调用 `scripts/remove-answerme-result-token.ps1` 精确清理凭证。
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# AnswerMe 问卷模板规格
|
|
2
|
+
|
|
3
|
+
## 校验总则
|
|
4
|
+
|
|
5
|
+
创建脚本在任何网络请求前严格校验紧凑输入和完整模板;本文件是字段、类型、范围、唯一性与 Unicode 码点规则的唯一权威。JSON 必须解析为对象,根、题目、选项和 `visual` 对象均拒绝未知字段;字段值不得靠字符串转换“修正”成另一种类型。
|
|
6
|
+
|
|
7
|
+
除 `body` 外,校验和存储前去除定义文本首尾空白;长度按 Unicode 码点计算,不按 UTF-16 code unit。JSON 字符串若含无法组成 Unicode 码点的未配对 UTF-16 代理项,必须在联网前拒绝。提供的文本字段去除空白后仍须满足下表的最小长度;可选字段省略时使用表中的默认值。
|
|
8
|
+
|
|
9
|
+
## 完整模板字段边界
|
|
10
|
+
|
|
11
|
+
根对象只允许 `schemaVersion`、`type`、`topic`、`intro`、`questions`、`allowAdditionalContext`、`expiresInSeconds`、`visual`:
|
|
12
|
+
|
|
13
|
+
| 字段 | 类型与规则 |
|
|
14
|
+
|---|---|
|
|
15
|
+
| `schemaVersion` | 必填整数,显式选择 `1` 或 `2`;`1` 拒绝 `body`、`text` 题型和 `maxLength` |
|
|
16
|
+
| `type` | 必填字符串,固定 `questionnaire` |
|
|
17
|
+
| `topic` | 必填字符串,1–100 Unicode 码点 |
|
|
18
|
+
| `intro` | 可选字符串,去除首尾空白后最多 1000 码点 |
|
|
19
|
+
| `questions` | 必填数组,1–20 题 |
|
|
20
|
+
| `allowAdditionalContext` | 可选布尔值,默认 `false`;提交补充说明最多 2000 码点 |
|
|
21
|
+
| `expiresInSeconds` | 可选整数,1–604800,默认 `3600` |
|
|
22
|
+
| `visual` | 必填对象,只允许 `{ "theme": "auto" }` |
|
|
23
|
+
|
|
24
|
+
选择题对象只允许以下字段;v2 额外允许 `body`:
|
|
25
|
+
|
|
26
|
+
| 字段 | 类型与规则 |
|
|
27
|
+
|---|---|
|
|
28
|
+
| `id` | 必填非空字符串;问卷内唯一、大小写敏感 |
|
|
29
|
+
| `type` | 必填字符串:`single-choice` 或 `multiple-choice` |
|
|
30
|
+
| `title` | 必填字符串,1–1000 码点 |
|
|
31
|
+
| `shortLabel` | 必填字符串,1–20 码点 |
|
|
32
|
+
| `required` | 必填布尔值 |
|
|
33
|
+
| `minSelections` / `maxSelections` | 必填整数;单选固定 `1/1`;多选满足 `1 ≤ min ≤ max`,`max` 为 2–20 且不超过可选项总数;启用自定义答案时自定义项计作一项 |
|
|
34
|
+
| `options` | 必填数组,每题 2–20 项 |
|
|
35
|
+
| `allowCustomAnswer` | 必填布尔值,是否允许其他/自定义答案 |
|
|
36
|
+
| `customAnswerMaxLength` | 可选整数;仅在允许自定义答案时提供,1–2000,默认 `2000` |
|
|
37
|
+
|
|
38
|
+
每个选项对象只允许 `id`、`label`、`description`:`id` 为必填非空字符串,题内唯一、大小写敏感;`label` 为必填字符串且 1–100 码点;`description` 为可选字符串且去除首尾空白后最多 500 码点。
|
|
39
|
+
|
|
40
|
+
v2 的 `body` 是可选 Markdown 字符串,原始输入最多 10000 Unicode 码点;先检查原始长度,全空白则省略,非空则保留原始内容及缩进。仅正文解释 Markdown:段落、强调、列表、引用和代码;标题、选项和答案仍为纯文本,HTML、外部图片不启用,链接显示为不可点击的文字。
|
|
41
|
+
|
|
42
|
+
v2 开放题使用 `type=text`,仅允许 `id`、`type`、`title`、`shortLabel`、`required`、`body`、`maxLength`。通用字段沿用上述规则,`maxLength` 是可选整数 1–2000,默认 2000。开放题禁止选项、选择数量和自定义选项字段(包括值为 null);选择题禁止 `maxLength`。开放题提交 `{questionId, customAnswer}`,禁止 `optionId` / `optionIds`;答案先校验原始码点长度,再去除首尾空白,提供时必须非空。未答可选题从 answers 省略,必填题必须作答。
|
|
43
|
+
|
|
44
|
+
## 紧凑输入字段边界
|
|
45
|
+
|
|
46
|
+
紧凑根对象只允许 `topic`、`intro`、`questions`、`allowAdditionalContext`、`expiresInSeconds`;`topic`、`intro`、题目 `title` 和选项标签遵循完整模板的文本规则。紧凑选择题只允许 `title`、`type`、`body`、`options`、`minSelections`、`maxSelections`,其中 `type` 为 `single-choice` 或 `multiple-choice`,`options` 是 2–20 个非空字符串。紧凑开放题只允许 `title`、`type=text`、`body`、`maxLength`。正文和开放题长度沿用完整模板规则。任何题提供 `body`(即使全空白)或包含开放题时自动选择 schemaVersion=2,否则为 1。紧凑输入不接受 `schemaVersion`、`visual`、ID、`shortLabel`、`required`、`allowCustomAnswer` 或其他未知字段。
|
|
47
|
+
|
|
48
|
+
紧凑适配器按题目顺序生成稳定的 `q1`、`q1-o1` 等 ID,设置 `required=true`,并从标题生成不超过 20 码点的 `shortLabel`。单选范围固定为 `1/1`,不得提供范围字段;多选默认 `minSelections=1`、`maxSelections=选项数`,显式范围仍须满足完整模板规则。
|
|
49
|
+
|
|
50
|
+
### 最小开放题示例
|
|
51
|
+
|
|
52
|
+
以下 JSON 作为 `-CompactQuestionnaireJson` 输入:
|
|
53
|
+
|
|
54
|
+
```json
|
|
55
|
+
{
|
|
56
|
+
"topic": "验收标准",
|
|
57
|
+
"questions": [
|
|
58
|
+
{ "title": "怎样判断这次交付符合预期?", "type": "text" }
|
|
59
|
+
]
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## 设计纪律
|
|
64
|
+
|
|
65
|
+
题型选择、问题顺序和推荐条件遵循 [ask-when-needed 的问题设计规则](../../ask-when-needed/SKILL.md#设计问题)。以下只补充问卷字段与展示要求:
|
|
66
|
+
|
|
67
|
+
- 多选题应明确最少与最多选择数。
|
|
68
|
+
- 选择题中,若用户可能无法选中预设项,开启 `allowCustomAnswer`。多选题中自定义答案可与预设项组合,并计入选择数。
|
|
69
|
+
- 仅当问卷可能遗漏跨题信息或用户需要补充对 Agent 的要求时启用 `allowAdditionalContext`。
|
|
70
|
+
- 选择题有推荐项时只标记一项,置于第一项;推荐依据、适用条件和主要代价写入 `body` 或选项 `description`(完整模板)。开放题的建议写入 `body`,不伪造选项或预填用户答案;紧凑输入仍只使用其允许字段。
|
|
71
|
+
- 不设置默认选择,不用视觉权重诱导,不隐藏或移动关键提交按钮。
|
|
72
|
+
- `id` 使用稳定英文 kebab-case;修改文案不应改变 ID。
|
|
73
|
+
- 不把秘密、个人敏感信息或生产凭证放进题目、说明或答案。
|
|
74
|
+
|
|
75
|
+
## 单题模板
|
|
76
|
+
|
|
77
|
+
```json
|
|
78
|
+
{
|
|
79
|
+
"schemaVersion": 1,
|
|
80
|
+
"type": "questionnaire",
|
|
81
|
+
"topic": "数据库选择",
|
|
82
|
+
"intro": "请选择本轮实现采用的数据库。",
|
|
83
|
+
"questions": [
|
|
84
|
+
{
|
|
85
|
+
"id": "database",
|
|
86
|
+
"type": "single-choice",
|
|
87
|
+
"title": "本轮使用哪种数据库?",
|
|
88
|
+
"shortLabel": "数据库",
|
|
89
|
+
"required": true,
|
|
90
|
+
"minSelections": 1,
|
|
91
|
+
"maxSelections": 1,
|
|
92
|
+
"options": [
|
|
93
|
+
{ "id": "sqlite", "label": "SQLite [推荐]", "description": "本地依赖更少。" },
|
|
94
|
+
{ "id": "postgresql", "label": "PostgreSQL", "description": "适合后续多实例,但运维成本更高。" }
|
|
95
|
+
],
|
|
96
|
+
"allowCustomAnswer": true,
|
|
97
|
+
"customAnswerMaxLength": 500
|
|
98
|
+
}
|
|
99
|
+
],
|
|
100
|
+
"allowAdditionalContext": false,
|
|
101
|
+
"expiresInSeconds": 3600,
|
|
102
|
+
"visual": { "theme": "auto" }
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## 多选与补充说明模板
|
|
107
|
+
|
|
108
|
+
```json
|
|
109
|
+
{
|
|
110
|
+
"schemaVersion": 1,
|
|
111
|
+
"type": "questionnaire",
|
|
112
|
+
"topic": "本轮交付范围",
|
|
113
|
+
"questions": [
|
|
114
|
+
{
|
|
115
|
+
"id": "deliverables",
|
|
116
|
+
"type": "multiple-choice",
|
|
117
|
+
"title": "本轮需要包含哪些交付物?",
|
|
118
|
+
"shortLabel": "交付物",
|
|
119
|
+
"required": true,
|
|
120
|
+
"minSelections": 2,
|
|
121
|
+
"maxSelections": 3,
|
|
122
|
+
"options": [
|
|
123
|
+
{ "id": "code", "label": "代码" },
|
|
124
|
+
{ "id": "tests", "label": "自动化测试" },
|
|
125
|
+
{ "id": "docs", "label": "使用文档" }
|
|
126
|
+
],
|
|
127
|
+
"allowCustomAnswer": true,
|
|
128
|
+
"customAnswerMaxLength": 500
|
|
129
|
+
}
|
|
130
|
+
],
|
|
131
|
+
"allowAdditionalContext": true,
|
|
132
|
+
"expiresInSeconds": 3600,
|
|
133
|
+
"visual": { "theme": "auto" }
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## 提交结果映射
|
|
138
|
+
|
|
139
|
+
按 `questionId` 建立映射;单选预设答案读取 `optionId`,多选预设答案读取 `optionIds`,自定义答案和开放题答案读取 `customAnswer`,由对应题型区分含义。`additionalContext` 是问卷外补充,不属于任何 `questionId`。缺失的可选题标记为 `unknown`,不得套用推荐项。
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
function Test-AnswerMeLoopbackHost {
|
|
2
|
+
param([Parameter(Mandatory = $true)][Uri]$Uri)
|
|
3
|
+
|
|
4
|
+
$hostName = $Uri.DnsSafeHost
|
|
5
|
+
return $hostName.Equals('localhost', [StringComparison]::OrdinalIgnoreCase) -or
|
|
6
|
+
$hostName.Equals('127.0.0.1', [StringComparison]::Ordinal) -or
|
|
7
|
+
$hostName.Equals('::1', [StringComparison]::Ordinal)
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function Resolve-AnswerMeApiBaseUrl {
|
|
11
|
+
param(
|
|
12
|
+
[AllowNull()][string]$ApiBaseUrl,
|
|
13
|
+
[switch]$AllowInsecureLoopbackHttpForTest
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
if ([string]::IsNullOrWhiteSpace($ApiBaseUrl)) {
|
|
17
|
+
return $null
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
$parsedBaseUrl = $null
|
|
21
|
+
if (-not [Uri]::TryCreate($ApiBaseUrl, [UriKind]::Absolute, [ref]$parsedBaseUrl)) {
|
|
22
|
+
throw 'API base URL must be an absolute HTTPS URL.'
|
|
23
|
+
}
|
|
24
|
+
if (-not [string]::IsNullOrEmpty($parsedBaseUrl.UserInfo) -or
|
|
25
|
+
-not [string]::IsNullOrEmpty($parsedBaseUrl.Query) -or
|
|
26
|
+
-not [string]::IsNullOrEmpty($parsedBaseUrl.Fragment) -or
|
|
27
|
+
$parsedBaseUrl.AbsolutePath -notin @('', '/')) {
|
|
28
|
+
throw 'API base URL must not include credentials, a path, a query, or a fragment.'
|
|
29
|
+
}
|
|
30
|
+
if ($parsedBaseUrl.Scheme -eq 'https') {
|
|
31
|
+
return $parsedBaseUrl
|
|
32
|
+
}
|
|
33
|
+
if ($parsedBaseUrl.Scheme -eq 'http' -and
|
|
34
|
+
$AllowInsecureLoopbackHttpForTest -and
|
|
35
|
+
(Test-AnswerMeLoopbackHost -Uri $parsedBaseUrl)) {
|
|
36
|
+
return $parsedBaseUrl
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
throw 'API base URL must use HTTPS; HTTP is limited to an explicit loopback test override.'
|
|
40
|
+
}
|