@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.
- package/.pi/dist/lib/knowledge/session-scanner.js +8 -22
- package/.pi/dist/lib/working-directory.js +4 -0
- package/.pi/extensions/knowledge.ts +3 -9
- package/.pi/extensions/workflows/cloud/activation.ts +2 -2
- package/.pi/extensions/workflows/sdd.ts +2 -2
- package/.pi/extensions/workflows/vibe.ts +2 -2
- package/.pi/extensions/workflows/workspace-guard.ts +3 -3
- package/.pi/lib/knowledge/session-scanner.ts +5 -21
- package/.pi/lib/working-directory.ts +5 -0
- package/package.json +1 -1
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { createHash, randomUUID } from "node:crypto";
|
|
2
2
|
import { readFileSync, readdirSync, statSync } from "node:fs";
|
|
3
|
-
import { resolve
|
|
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 {
|
|
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
|
|
209
|
-
|
|
210
|
-
|
|
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
|
-
|
|
224
|
-
return
|
|
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
|
|
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
|
|
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 {
|
|
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
|
|
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 {
|
|
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(
|
|
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 {
|
|
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(
|
|
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 {
|
|
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(
|
|
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 {
|
|
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(
|
|
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
|
|
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
|
|
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 {
|
|
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
|
|
202
|
-
|
|
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
|
|
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,
|