helloloop 0.7.0 → 0.7.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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "helloloop",
3
- "version": "0.7.0",
3
+ "version": "0.7.1",
4
4
  "description": "HelloLoop 的 Claude Code 原生插件元数据,用于多 CLI 宿主分发。",
5
5
  "author": {
6
6
  "name": "HelloLoop"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "helloloop",
3
- "version": "0.7.0",
3
+ "version": "0.7.1",
4
4
  "description": "面向 Codex CLI、Claude Code、Gemini CLI 的多宿主开发工作流插件,Codex 路径为首发与参考实现。",
5
5
  "author": {
6
6
  "name": "HelloLoop"
@@ -17,7 +17,7 @@
17
17
  "interface": {
18
18
  "displayName": "HelloLoop",
19
19
  "shortDescription": "显式调用后按 backlog 持续开发与验证",
20
- "longDescription": "HelloLoop 把基于 backlog 的持续开发能力封装为官方 Codex 插件 bundle。只有在用户显式调用 helloloop skill,或明确要求使用 HelloLoop 时才应介入;进入后默认优先走 npx helloloop 主 CLI 流程:支持 npx helloloop、npx helloloop <PATH>、npx helloloop codex|claude|gemini ...,先分析、再展示确认单、确认后自动接续推进;运行中按无人值守自动恢复持续推进主线。",
20
+ "longDescription": "HelloLoop 把基于 backlog 的持续开发能力封装为官方 Codex 插件 bundle。只有在用户显式调用 helloloop skill 时才应介入;进入后默认优先走 npx helloloop 主 CLI 流程:支持 npx helloloop、npx helloloop <PATH>、npx helloloop codex|claude|gemini ...,先分析、再展示确认单、确认后自动接续推进;运行中按无人值守自动恢复持续推进主线。",
21
21
  "developerName": "HelloLoop",
22
22
  "category": "Coding",
23
23
  "capabilities": [
@@ -25,7 +25,7 @@
25
25
  "Write"
26
26
  ],
27
27
  "defaultPrompt": [
28
- "只有当用户显式调用 $helloloop / #helloloop / helloloop:helloloop,或明确要求使用 HelloLoop 时,才进入 npx helloloop 主 CLI 流程;普通 Codex 会话不要自动接管。进入后优先执行 npx helloloop 或 npx helloloop <PATH>;如果用户明确指定执行引擎,也允许使用 npx helloloop codex|claude|gemini ...。启动前确认一次,启动后按无人值守自动恢复与主线续跑执行,不要在对话里手工模拟流程。"
28
+ "只有当用户显式调用 $helloloop / #helloloop / helloloop:helloloop 时,才进入 npx helloloop 主 CLI 流程;普通 Codex 会话不要自动接管。仅仅提到 helloloop 仓库、插件名、README、代码、测试、issue、release、npm 包名,都不算调用。进入后优先执行 npx helloloop 或 npx helloloop <PATH>;如果用户明确指定执行引擎,也允许使用 npx helloloop codex|claude|gemini ...。启动前确认一次,启动后按无人值守自动恢复与主线续跑执行,不要在对话里手工模拟流程。"
29
29
  ],
30
30
  "brandColor": "#0F766E"
31
31
  }
package/README.md CHANGED
@@ -19,6 +19,7 @@
19
19
  这意味着:
20
20
 
21
21
  - 三宿主都只在用户显式调用 `helloloop` 时介入;普通会话不会被 HelloLoop 自动接管
22
+ - 在 `Codex` 中,只有显式输入 `$helloloop` / `#helloloop` / `helloloop:helloloop` 才算调用;仅仅提到 `helloloop` 仓库、README、代码、测试、release、npm 包名,都不算调用
22
23
  - 无论在终端还是在 `Codex` / `Claude` / `Gemini` 宿主内,只要用户未明确指定引擎,`HelloLoop` 都会先询问本轮执行引擎
23
24
  - 当前宿主、项目历史、用户历史只作为推荐依据,不会自动替你选中引擎
24
25
  - 如果你已经显式指定,或已经在首轮确认中明确选定了引擎,本轮就固定按该引擎执行
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "helloloop",
3
- "version": "0.7.0",
3
+ "version": "0.7.1",
4
4
  "description": "HelloLoop 的 Claude Code 原生插件。",
5
5
  "author": {
6
6
  "name": "HelloLoop"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "helloloop",
3
- "version": "0.7.0",
3
+ "version": "0.7.1",
4
4
  "description": "HelloLoop 的 Gemini CLI 原生扩展,用于按开发文档接续推进项目开发。",
5
5
  "contextFileName": "GEMINI.md",
6
6
  "excludeTools": [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "helloloop",
3
- "version": "0.7.0",
3
+ "version": "0.7.1",
4
4
  "description": "面向 Codex CLI、Claude Code、Gemini CLI 的多宿主开发工作流插件",
5
5
  "author": "HelloLoop",
6
6
  "license": "Apache-2.0",
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: helloloop
3
- description: 仅当用户显式调用 `$helloloop` / `#helloloop` / `helloloop:helloloop`,或明确要求使用 HelloLoop 按开发文档持续接续开发时使用。
3
+ description: 仅当用户显式调用 `$helloloop` / `#helloloop` / `helloloop:helloloop` 时使用。
4
4
  ---
5
5
 
6
6
  # HelloLoop
@@ -9,7 +9,8 @@ description: 仅当用户显式调用 `$helloloop` / `#helloloop` / `helloloop:h
9
9
 
10
10
  ## 强制入口规则
11
11
 
12
- - 未显式调用 `helloloop`,且用户也没有明确要求“使用 HelloLoop / 使用 helloloop 插件 / HelloLoop 流程”时,不允许接管普通 Codex 会话。
12
+ - 只有用户显式调用 `$helloloop` / `#helloloop` / `helloloop:helloloop` 时,才允许进入 HelloLoop;未显式调用时,不允许接管普通 Codex 会话。
13
+ - 仅仅提到 `helloloop` 仓库、插件名、README、代码、测试、issue、release、npm 包名,都不算调用 HelloLoop。
13
14
  - 用户显式调用 `$helloloop` / `#helloloop` / `helloloop:helloloop` 时,默认必须优先执行 `npx helloloop` 或 `npx helloloop <PATH>`;如果用户又明确指定了执行引擎,也允许使用 `npx helloloop codex|claude|gemini ...`。
14
15
  - 用户没有明确指定执行引擎时,不允许由 skill 自行补成 `codex` / `claude` / `gemini`;必须让 `HelloLoop` 先完成引擎确认。
15
16
  - 不允许在对话里手工模拟 `HelloLoop` 的分析、确认单、backlog 编排和自动续跑流程来代替 CLI。
@@ -1,4 +1,5 @@
1
1
  import fs from "node:fs";
2
+ import os from "node:os";
2
3
  import path from "node:path";
3
4
 
4
5
  import { fileExists } from "./common.mjs";
@@ -59,6 +60,26 @@ const IGNORED_PROJECT_SEGMENTS = new Set([
59
60
  "venv",
60
61
  ]);
61
62
 
63
+ const PREFERRED_ANCESTOR_SEGMENTS = new Set([
64
+ ".cache",
65
+ ".next",
66
+ ".nuxt",
67
+ ".pnpm",
68
+ ".turbo",
69
+ ".venv",
70
+ ".yarn",
71
+ "__pycache__",
72
+ "build",
73
+ "cache",
74
+ "coverage",
75
+ "dist",
76
+ "node_modules",
77
+ "out",
78
+ "target",
79
+ "vendor",
80
+ "venv",
81
+ ]);
82
+
62
83
  function listImmediateDirectories(directoryPath) {
63
84
  if (!pathExists(directoryPath) || !fs.statSync(directoryPath).isDirectory()) {
64
85
  return [];
@@ -99,13 +120,52 @@ function hasIgnoredProjectBasename(targetPath) {
99
120
  return IGNORED_PROJECT_SEGMENTS.has(path.basename(targetPath).toLowerCase());
100
121
  }
101
122
 
123
+ function canonicalPath(targetPath) {
124
+ if (!targetPath) {
125
+ return "";
126
+ }
127
+
128
+ try {
129
+ const resolved = fs.realpathSync.native
130
+ ? fs.realpathSync.native(targetPath)
131
+ : fs.realpathSync(targetPath);
132
+ return process.platform === "win32" ? resolved.toLowerCase() : resolved;
133
+ } catch {
134
+ const resolved = path.resolve(targetPath);
135
+ return process.platform === "win32" ? resolved.toLowerCase() : resolved;
136
+ }
137
+ }
138
+
139
+ function isImplicitHomeDirectory(targetPath) {
140
+ return Boolean(targetPath) && canonicalPath(targetPath) === canonicalPath(os.homedir());
141
+ }
142
+
143
+ function isUserProfileLikeDirectory(targetPath) {
144
+ if (!targetPath) {
145
+ return false;
146
+ }
147
+
148
+ const resolved = path.resolve(targetPath);
149
+ const normalized = resolved.replaceAll("\\", "/");
150
+ if (/^[A-Za-z]:\/Users\/[^/]+$/i.test(normalized)) {
151
+ return true;
152
+ }
153
+ if (/^\/Users\/[^/]+$/.test(normalized)) {
154
+ return true;
155
+ }
156
+ if (/^\/home\/[^/]+$/.test(normalized)) {
157
+ return true;
158
+ }
159
+ return false;
160
+ }
161
+
102
162
  function choosePreferredCandidate(candidates, directory) {
103
163
  return candidates.find((candidate) => {
104
164
  const relativeToLeaf = path.relative(candidate, directory);
105
165
  return relativeToLeaf
106
166
  .split(/[\\/]+/)
107
167
  .filter(Boolean)
108
- .some((segment) => IGNORED_PROJECT_SEGMENTS.has(segment.toLowerCase()));
168
+ .some((segment) => PREFERRED_ANCESTOR_SEGMENTS.has(segment.toLowerCase()));
109
169
  })
110
170
  || candidates.find((candidate) => !hasIgnoredProjectBasename(candidate))
111
171
  || candidates[0]
@@ -233,6 +293,10 @@ export function findPreferredRepoRootFromPath(startPath) {
233
293
  return current;
234
294
  }
235
295
 
296
+ if (isImplicitHomeDirectory(current) || isUserProfileLikeDirectory(current)) {
297
+ continue;
298
+ }
299
+
236
300
  if (looksLikeStrongProjectRoot(current)) {
237
301
  strongCandidates.push(current);
238
302
  continue;