@hadooppei/hwcode 1.0.15 → 1.0.16

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,9 +1,9 @@
1
1
  import { createHash, randomUUID } from "node:crypto";
2
2
  import { readFileSync, readdirSync, statSync } from "node:fs";
3
- import { resolve, sep } from "node:path";
3
+ import { resolve } from "node:path";
4
4
  import { buildContextEntries, parseSessionEntries, } from "@earendil-works/pi-coding-agent";
5
5
  import { KNOWLEDGE_RUNTIME_DEFAULTS } from "../runtime/defaults.js";
6
- import { findLatestWorkflowRoot } from "../working-directory.js";
6
+ import { canonicalizeDirectory } from "../working-directory.js";
7
7
  import { knowledgeDeltaDigest } from "./extractor.js";
8
8
  import { sanitizeKnowledgeText } from "./sanitize.js";
9
9
  import { projectKnowledgeKey } from "./store.js";
@@ -205,27 +205,13 @@ function buildRecallQuery(entries, ids) {
205
205
  lines.push(...workflowLines.filter((line) => line.startsWith("Verified success:")));
206
206
  return lines.join("\n").slice(0, MAX_RECALL_QUERY_CHARS);
207
207
  }
208
- function projectRootForSession(header, branch) {
209
- const sessionRoot = resolve(header.cwd);
210
- const workflowRootValue = findLatestWorkflowRoot(branch);
211
- const workflowRoot = workflowRootValue ? resolve(workflowRootValue) : undefined;
212
- let workingDirectory = sessionRoot;
213
- for (const entry of branch.slice().reverse()) {
214
- if (entry.type !== "custom" || entry.customType !== "hwcode-working-directory"
215
- || !entry.data || typeof entry.data !== "object")
216
- continue;
217
- const cwd = entry.data.cwd;
218
- if (typeof cwd !== "string" || !cwd)
219
- continue;
220
- workingDirectory = resolve(cwd);
221
- break;
208
+ function projectRootForSession(header) {
209
+ try {
210
+ return canonicalizeDirectory(header.cwd);
222
211
  }
223
- if (workflowRoot && (workingDirectory === workflowRoot || workingDirectory.startsWith(`${workflowRoot}${sep}`))) {
224
- return workflowRoot;
212
+ catch {
213
+ return resolve(header.cwd);
225
214
  }
226
- if (workingDirectory === sessionRoot || workingDirectory.startsWith(`${sessionRoot}${sep}`))
227
- return sessionRoot;
228
- return workingDirectory;
229
215
  }
230
216
  export function discoverSessionFiles(root) {
231
217
  const files = [];
@@ -292,7 +278,7 @@ export function readReviewTask(sessionFile, cursor, now = Date.now()) {
292
278
  const sessionFileHash = hash(resolve(sessionFile), 16);
293
279
  const sessionKey = hash(header.id, 24);
294
280
  const reviewKey = hash(`${header.id}\0${firstEntryId}\0${lastEntryId}\0${deltaDigest}`);
295
- const projectRoot = projectRootForSession(header, branch);
281
+ const projectRoot = projectRootForSession(header);
296
282
  return {
297
283
  requestId: randomUUID(), reviewKey, sessionId: header.id, sessionKey, sessionFileHash,
298
284
  projectRoot, projectKey: projectKnowledgeKey(projectRoot),
@@ -39,6 +39,10 @@ export function getWorkingDirectoryState(source) {
39
39
  export function getWorkingDirectory(source) {
40
40
  return getWorkingDirectoryState(source).cwd;
41
41
  }
42
+ /** The immutable project root captured when the session was created. */
43
+ export function getSessionProjectRoot(source) {
44
+ return canonicalizeDirectory(source.getCwd());
45
+ }
42
46
  export function setWorkingDirectoryState(source, state) {
43
47
  workingDirectories.set(source.getSessionId(), state);
44
48
  }
@@ -1,6 +1,6 @@
1
1
  import { randomUUID } from "node:crypto";
2
2
  import { existsSync } from "node:fs";
3
- import { dirname, resolve, sep } from "node:path";
3
+ import { dirname } from "node:path";
4
4
  import { fileURLToPath } from "node:url";
5
5
  import { Worker } from "node:worker_threads";
6
6
 
@@ -14,7 +14,7 @@ import { matchKnowledge, recallKnowledge } from "../lib/knowledge/matcher.ts";
14
14
  import { loadKnowledgeById, loadKnowledgeSnapshot, projectKnowledgeKey } from "../lib/knowledge/store.ts";
15
15
  import type { KnowledgeWorkerInput, KnowledgeWorkerOutput } from "../lib/knowledge/worker-protocol.ts";
16
16
  import { KNOWLEDGE_RUNTIME_DEFAULTS } from "../lib/runtime/defaults.ts";
17
- import { findLatestWorkflowRoot, getWorkingDirectory } from "../lib/working-directory.ts";
17
+ import { getSessionProjectRoot } from "../lib/working-directory.ts";
18
18
 
19
19
  interface ActiveReview {
20
20
  requestId: string;
@@ -245,13 +245,7 @@ function configureForContext(ctx: ExtensionContext): void {
245
245
  }
246
246
 
247
247
  function currentProject(ctx: ExtensionContext): { root: string; key: string } {
248
- const workingDirectory = resolve(getWorkingDirectory(ctx.sessionManager));
249
- const workflowRootValue = findLatestWorkflowRoot(ctx.sessionManager.getEntries());
250
- const workflowRoot = workflowRootValue ? resolve(workflowRootValue) : undefined;
251
- const root = workflowRoot
252
- && (workingDirectory === workflowRoot || workingDirectory.startsWith(`${workflowRoot}${sep}`))
253
- ? workflowRoot
254
- : workingDirectory;
248
+ const root = getSessionProjectRoot(ctx.sessionManager);
255
249
  return { root, key: projectKnowledgeKey(root) };
256
250
  }
257
251
 
@@ -9,7 +9,7 @@ import { modelConfigurationIssue } from "../../../lib/models/readiness.ts";
9
9
  import { CLOUD_RUNTIME_DEFAULTS } from "../../../lib/runtime/defaults.ts";
10
10
  import { remoteRunnerPaths, userRuntimePaths } from "../../../lib/runtime/paths.ts";
11
11
  import { canonicalizeWorkspaceRoot } from "../../../lib/workflow-guard.ts";
12
- import { getWorkingDirectory } from "../../../lib/working-directory.ts";
12
+ import { getSessionProjectRoot } from "../../../lib/working-directory.ts";
13
13
  import { checkProviderCli, formatValidationFailure, validateCloudCredentials } from "../../../lib/workflows/cloud/adapters.ts";
14
14
  import { cloudTerraformTemplateSource, listCloudTerraformTemplates, materializeCloudTerraformTemplate, type CloudTerraformTemplate } from "../../../lib/workflows/cloud/bundles.ts";
15
15
  import { CLOUD_PROVIDERS, getCloudProvider, inaccessibleCloudCliMessage, missingCloudCliMessage, type CloudCredentials, type CloudVendorId } from "../../../lib/workflows/cloud/providers.ts";
@@ -126,7 +126,7 @@ export async function activateCloudWorkflow(runtime: CloudExtensionRuntime, args
126
126
  if (!ctx.isIdle()) { notify(ctx, "请等待当前响应完成后再启动 HWCode Cloud。", "warning"); return; }
127
127
  if (!(await ensureConversationModel(ctx))) return;
128
128
 
129
- const root = canonicalizeWorkspaceRoot(getWorkingDirectory(ctx.sessionManager));
129
+ const root = canonicalizeWorkspaceRoot(getSessionProjectRoot(ctx.sessionManager));
130
130
  const currentWorkflow = activeWorkflow(ctx.sessionManager.getEntries());
131
131
  if (currentWorkflow && currentWorkflow.mode !== "cloud") {
132
132
  notify(ctx, `当前会话已有 ${currentWorkflow.mode} workflow。请新建 session 后再启动 HWCode Cloud。`, "warning");
@@ -10,7 +10,7 @@ import { notify } from "../../lib/extension-ui.ts";
10
10
  import {
11
11
  canonicalizeWorkspaceRoot,
12
12
  } from "../../lib/workflow-guard.ts";
13
- import { getWorkingDirectory } from "../../lib/working-directory.ts";
13
+ import { getSessionProjectRoot } from "../../lib/working-directory.ts";
14
14
  import {
15
15
  WORKFLOW_STATE_TYPE,
16
16
  activeWorkflow,
@@ -94,7 +94,7 @@ export function registerSddWorkflow(pi: ExtensionAPI) {
94
94
  return;
95
95
  }
96
96
 
97
- const root = canonicalizeWorkspaceRoot(getWorkingDirectory(ctx.sessionManager));
97
+ const root = canonicalizeWorkspaceRoot(getSessionProjectRoot(ctx.sessionManager));
98
98
  const existing = activeWorkflow(ctx.sessionManager.getEntries());
99
99
  if (existing) {
100
100
  notify(
@@ -6,7 +6,7 @@ import { notify } from "../../lib/extension-ui.ts";
6
6
  import {
7
7
  canonicalizeWorkspaceRoot,
8
8
  } from "../../lib/workflow-guard.ts";
9
- import { getWorkingDirectory } from "../../lib/working-directory.ts";
9
+ import { getSessionProjectRoot } from "../../lib/working-directory.ts";
10
10
  import {
11
11
  WORKFLOW_STATE_TYPE,
12
12
  activeWorkflow,
@@ -24,7 +24,7 @@ export function registerVibeWorkflow(pi: ExtensionAPI) {
24
24
  return;
25
25
  }
26
26
 
27
- const root = canonicalizeWorkspaceRoot(getWorkingDirectory(ctx.sessionManager));
27
+ const root = canonicalizeWorkspaceRoot(getSessionProjectRoot(ctx.sessionManager));
28
28
  const existing = activeWorkflow(ctx.sessionManager.getEntries());
29
29
  if (existing) {
30
30
  notify(
@@ -7,7 +7,7 @@ import { notify } from "../../lib/extension-ui.ts";
7
7
  import {
8
8
  canonicalizeWorkspaceRoot,
9
9
  } from "../../lib/workflow-guard.ts";
10
- import { getWorkingDirectory } from "../../lib/working-directory.ts";
10
+ import { getSessionProjectRoot } from "../../lib/working-directory.ts";
11
11
  import {
12
12
  WORKFLOW_EXTERNAL_AUDIT_TYPE,
13
13
  WORKFLOW_STATE_TYPE,
@@ -47,13 +47,13 @@ export function registerWorkspaceGuard(pi: ExtensionAPI) {
47
47
  return;
48
48
  }
49
49
 
50
- const currentRoot = canonicalizeWorkspaceRoot(getWorkingDirectory(ctx.sessionManager));
50
+ const currentRoot = canonicalizeWorkspaceRoot(getSessionProjectRoot(ctx.sessionManager));
51
51
  if (currentRoot !== restored.root) {
52
52
  activeState = undefined;
53
53
  pi.appendEntry<WorkflowState>(WORKFLOW_STATE_TYPE, updateWorkflowState(restored, {
54
54
  status: "cancelled",
55
55
  phase: "root-changed",
56
- reason: "Stored workflow root no longer matches the current execution directory.",
56
+ reason: "Stored workflow root no longer matches the immutable session project root.",
57
57
  }));
58
58
  notify(ctx, "Stored HWCode workflow disabled because the current directory changed.", "warning");
59
59
  return;
@@ -1,13 +1,13 @@
1
1
  import { createHash, randomUUID } from "node:crypto";
2
2
  import { readFileSync, readdirSync, statSync } from "node:fs";
3
- import { resolve, sep } from "node:path";
3
+ import { resolve } from "node:path";
4
4
 
5
5
  import {
6
6
  buildContextEntries, parseSessionEntries, type SessionEntry, type SessionHeader,
7
7
  } from "@earendil-works/pi-coding-agent";
8
8
 
9
9
  import { KNOWLEDGE_RUNTIME_DEFAULTS } from "../runtime/defaults.ts";
10
- import { findLatestWorkflowRoot } from "../working-directory.ts";
10
+ import { canonicalizeDirectory } from "../working-directory.ts";
11
11
  import { knowledgeDeltaDigest } from "./extractor.ts";
12
12
  import { sanitizeKnowledgeText } from "./sanitize.ts";
13
13
  import { projectKnowledgeKey } from "./store.ts";
@@ -198,24 +198,8 @@ function buildRecallQuery(entries: SessionEntry[], ids: string[]): string {
198
198
  return lines.join("\n").slice(0, MAX_RECALL_QUERY_CHARS);
199
199
  }
200
200
 
201
- function projectRootForSession(header: SessionHeader, branch: SessionEntry[]): string {
202
- const sessionRoot = resolve(header.cwd);
203
- const workflowRootValue = findLatestWorkflowRoot(branch);
204
- const workflowRoot = workflowRootValue ? resolve(workflowRootValue) : undefined;
205
- let workingDirectory = sessionRoot;
206
- for (const entry of branch.slice().reverse()) {
207
- if (entry.type !== "custom" || entry.customType !== "hwcode-working-directory"
208
- || !entry.data || typeof entry.data !== "object") continue;
209
- const cwd = (entry.data as Record<string, unknown>).cwd;
210
- if (typeof cwd !== "string" || !cwd) continue;
211
- workingDirectory = resolve(cwd);
212
- break;
213
- }
214
- if (workflowRoot && (workingDirectory === workflowRoot || workingDirectory.startsWith(`${workflowRoot}${sep}`))) {
215
- return workflowRoot;
216
- }
217
- if (workingDirectory === sessionRoot || workingDirectory.startsWith(`${sessionRoot}${sep}`)) return sessionRoot;
218
- return workingDirectory;
201
+ function projectRootForSession(header: SessionHeader): string {
202
+ try { return canonicalizeDirectory(header.cwd); } catch { return resolve(header.cwd); }
219
203
  }
220
204
 
221
205
  export function discoverSessionFiles(root: string): string[] {
@@ -266,7 +250,7 @@ export function readReviewTask(
266
250
  const sessionFileHash = hash(resolve(sessionFile), 16);
267
251
  const sessionKey = hash(header.id, 24);
268
252
  const reviewKey = hash(`${header.id}\0${firstEntryId}\0${lastEntryId}\0${deltaDigest}`);
269
- const projectRoot = projectRootForSession(header, branch);
253
+ const projectRoot = projectRootForSession(header);
270
254
  return {
271
255
  requestId: randomUUID(), reviewKey, sessionId: header.id, sessionKey, sessionFileHash,
272
256
  projectRoot, projectKey: projectKnowledgeKey(projectRoot),
@@ -69,6 +69,11 @@ export function getWorkingDirectory(source: SessionDirectorySource): string {
69
69
  return getWorkingDirectoryState(source).cwd;
70
70
  }
71
71
 
72
+ /** The immutable project root captured when the session was created. */
73
+ export function getSessionProjectRoot(source: Pick<SessionDirectorySource, "getCwd">): string {
74
+ return canonicalizeDirectory(source.getCwd());
75
+ }
76
+
72
77
  export function setWorkingDirectoryState(
73
78
  source: SessionDirectorySource,
74
79
  state: WorkingDirectoryState,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hadooppei/hwcode",
3
- "version": "1.0.15",
3
+ "version": "1.0.16",
4
4
  "description": "A customizable terminal coding agent with local-model support and HWCode workflows.",
5
5
  "type": "module",
6
6
  "bin": {