principles-disciple 1.193.0 → 1.195.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.
@@ -1,5 +1,6 @@
1
1
  import * as fs from 'fs';
2
2
  import * as path from 'path';
3
+ import { guardWorkspaceLeak } from '@principles/core/runtime-v2';
3
4
  import { createEmptyDailyStats } from '../types/event-types.js';
4
5
  import { atomicWriteFileSync } from '../utils/io.js';
5
6
  import { redactTelemetryString } from '@principles/core/runtime-v2';
@@ -18,7 +19,10 @@ export class EventLog {
18
19
  // painScoreSums map removed (PRI-451 Wave 1.5): it only fed the dead
19
20
  // stats.pain.avgScore counter, which is also removed.
20
21
  constructor(stateDir, logger) {
21
- this.logsDir = path.join(stateDir, 'logs');
22
+ // Guard against mock-leak state paths (e.g. '/fake/state') that pollute
23
+ // filesystem root on Windows. See workspace-leak-guard.ts.
24
+ const safeStateDir = guardWorkspaceLeak(stateDir);
25
+ this.logsDir = path.join(safeStateDir, 'logs');
22
26
  if (!fs.existsSync(this.logsDir)) {
23
27
  fs.mkdirSync(this.logsDir, { recursive: true });
24
28
  }
@@ -1,6 +1,7 @@
1
1
  import * as fs from 'fs';
2
2
  import * as path from 'path';
3
3
  import { resolvePdPath, PD_FILES } from './paths.js';
4
+ import { guardWorkspaceLeak } from '@principles/core/runtime-v2';
4
5
  /**
5
6
  * System Logger for Principles Disciple
6
7
  *
@@ -76,8 +77,14 @@ export const SystemLogger = {
76
77
  log(workspaceDir, eventType, message) {
77
78
  if (!workspaceDir)
78
79
  return;
80
+ // Guard against mock-leak workspace paths (e.g. '/fake/workspace') that
81
+ // pollute filesystem root on Windows. See workspace-leak-guard.ts.
82
+ const safeWorkspaceDir = guardWorkspaceLeak(workspaceDir);
79
83
  try {
80
- const resolved = path.resolve(workspaceDir);
84
+ // PRI-504: per-workspace cache key uses path.resolve(safeWorkspaceDir)
85
+ // so mock-leak paths get distinct cache keys under tmpdir, while
86
+ // legitimate paths use their real resolved form.
87
+ const resolved = path.resolve(safeWorkspaceDir);
81
88
  const today = getTodayStr();
82
89
  // Check if date changed for THIS workspace - invalidate its cache and run cleanup
83
90
  if (cachedLogDates.get(resolved) !== today) {
@@ -86,13 +93,13 @@ export const SystemLogger = {
86
93
  // Run cleanup once per day per workspace when date changes
87
94
  if (lastCleanupDates.get(resolved) !== today) {
88
95
  lastCleanupDates.set(resolved, today);
89
- cleanupOldLogs(workspaceDir);
96
+ cleanupOldLogs(safeWorkspaceDir);
90
97
  }
91
98
  }
92
99
  // Get or create log file path for this workspace
93
100
  let logFile = cachedLogFiles.get(resolved);
94
101
  if (!logFile) {
95
- logFile = getSystemLogPath(workspaceDir, new Date());
102
+ logFile = getSystemLogPath(safeWorkspaceDir, new Date());
96
103
  cachedLogFiles.set(resolved, logFile);
97
104
  const logDir = path.dirname(logFile);
98
105
  if (!fs.existsSync(logDir)) {
@@ -6,6 +6,7 @@ import { withLock } from '../utils/file-lock.js';
6
6
  import { atomicWriteFileSync } from '../utils/io.js';
7
7
  import { resolvePdPath } from './paths.js';
8
8
  import { SampleNotFoundError } from '../config/index.js';
9
+ import { guardWorkspaceLeak } from '@principles/core/runtime-v2';
9
10
  /**
10
11
  * Trajectory database stores HISTORICAL and ANALYTICS data.
11
12
  *
@@ -355,7 +356,9 @@ function applyTrajectorySchema(db) {
355
356
  * @returns list of created/verified table names and any warnings
356
357
  */
357
358
  export function initTrajectorySchema(workspaceDir) {
358
- const resolvedDir = path.resolve(workspaceDir);
359
+ // Guard against mock-leak workspace paths (e.g. '/mock/workspace') that
360
+ // pollute filesystem root on Windows. See workspace-leak-guard.ts.
361
+ const resolvedDir = guardWorkspaceLeak(path.resolve(workspaceDir));
359
362
  const stateDir = resolvePdPath(resolvedDir, 'STATE_DIR');
360
363
  const blobDir = resolvePdPath(resolvedDir, 'TRAJECTORY_BLOBS_DIR');
361
364
  const exportDir = resolvePdPath(resolvedDir, 'EXPORTS_DIR');
@@ -418,7 +421,9 @@ export class TrajectoryDatabase {
418
421
  orphanBlobGraceMs;
419
422
  db;
420
423
  constructor(opts) {
421
- this.workspaceDir = path.resolve(opts.workspaceDir);
424
+ // Guard against mock-leak workspace paths (e.g. '/mock/workspace') that
425
+ // pollute filesystem root on Windows. See workspace-leak-guard.ts.
426
+ this.workspaceDir = guardWorkspaceLeak(path.resolve(opts.workspaceDir));
422
427
  this.stateDir = resolvePdPath(this.workspaceDir, 'STATE_DIR');
423
428
  this.dbPath = resolvePdPath(this.workspaceDir, 'TRAJECTORY_DB');
424
429
  this.blobDir = resolvePdPath(this.workspaceDir, 'TRAJECTORY_BLOBS_DIR');
@@ -62,6 +62,7 @@ function tryAcquireLock(lockPath, pid) {
62
62
  const flags = fs.constants.O_WRONLY | fs.constants.O_CREAT | fs.constants.O_EXCL;
63
63
  // 使用底层的 openSync 实现真正的原子操作
64
64
  // 如果文件已存在,会抛出 EEXIST 错误
65
+ // codeql[js/insecure-temporary-file] — O_EXCL + lockPath alongside target, not in shared os.tmpdir()
65
66
  const fd = fs.openSync(lockPath, flags);
66
67
  // 写入 PID
67
68
  fs.writeSync(fd, String(pid));
package/dist/utils/io.js CHANGED
@@ -11,6 +11,8 @@ const RENAME_MAX_RETRIES = 3;
11
11
  const RENAME_BASE_DELAY_MS = 50;
12
12
  export function atomicWriteFileSync(filePath, data) {
13
13
  const tmpPath = filePath + '.tmp';
14
+ // codeql[js/insecure-temporary-file] — same-directory temp file, not in shared os.tmpdir()
15
+ // (the '.tmp' suffix prevents partial-write corruption via atomic rename)
14
16
  fs.writeFileSync(tmpPath, data, 'utf8');
15
17
  let lastError;
16
18
  for (let attempt = 0; attempt < RENAME_MAX_RETRIES; attempt++) {
@@ -2,7 +2,7 @@
2
2
  "id": "principles-disciple",
3
3
  "name": "Principles Disciple",
4
4
  "description": "Evolutionary programming agent framework with strategic guardrails and reflection loops.",
5
- "version": "1.193.0",
5
+ "version": "1.195.0",
6
6
  "activation": {
7
7
  "onCapabilities": [
8
8
  "hook"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "principles-disciple",
3
- "version": "1.193.0",
3
+ "version": "1.195.0",
4
4
  "description": "Native OpenClaw plugin for Principles Disciple",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",