principles-disciple 1.67.0 → 1.68.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.
- package/openclaw.plugin.json +3 -2
- package/package.json +1 -1
- package/scripts/sync-plugin.mjs +113 -28
- package/src/hooks/prompt.ts +3 -3
package/openclaw.plugin.json
CHANGED
|
@@ -2,9 +2,10 @@
|
|
|
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.
|
|
5
|
+
"version": "1.68.0",
|
|
6
6
|
"skills": [
|
|
7
|
-
"
|
|
7
|
+
"templates/langs/en/skills",
|
|
8
|
+
"templates/langs/zh/skills"
|
|
8
9
|
],
|
|
9
10
|
"configSchema": {
|
|
10
11
|
"type": "object",
|
package/package.json
CHANGED
package/scripts/sync-plugin.mjs
CHANGED
|
@@ -400,6 +400,7 @@ function verifyBundleContents() {
|
|
|
400
400
|
{ name: 'checkPainFlag', reason: 'pain flag detection' },
|
|
401
401
|
{ name: 'processEvolutionQueue', reason: 'queue processing' },
|
|
402
402
|
{ name: 'acquireQueueLock', reason: 'queue lock for pd-reflect and worker' },
|
|
403
|
+
{ name: 'write_pain_flag', reason: 'pain signal recording tool' },
|
|
403
404
|
];
|
|
404
405
|
|
|
405
406
|
const missing = [];
|
|
@@ -523,6 +524,26 @@ function verifyInstalledFingerprint() {
|
|
|
523
524
|
console.log('✅ Installed fingerprint verified');
|
|
524
525
|
}
|
|
525
526
|
|
|
527
|
+
/**
|
|
528
|
+
* Update the plugin version in openclaw.json after successful sync.
|
|
529
|
+
* This ensures the recorded version always matches the installed version.
|
|
530
|
+
*/
|
|
531
|
+
function updateInstalledPluginVersion(version) {
|
|
532
|
+
const configPath = join(OPENCLAW_DIR, 'openclaw.json');
|
|
533
|
+
try {
|
|
534
|
+
const raw = readFileSync(configPath, 'utf-8');
|
|
535
|
+
const config = JSON.parse(raw);
|
|
536
|
+
if (config?.plugins?.installs?.['principles-disciple']) {
|
|
537
|
+
config.plugins.installs['principles-disciple'].version = version;
|
|
538
|
+
config.plugins.installs['principles-disciple'].installedAt = new Date().toISOString();
|
|
539
|
+
writeFileAtomic(configPath, JSON.stringify(config, null, 2) + '\n');
|
|
540
|
+
console.log(`✅ openclaw.json updated: version=${version}`);
|
|
541
|
+
}
|
|
542
|
+
} catch (err) {
|
|
543
|
+
console.warn(`⚠️ Could not update openclaw.json: ${err.message}`);
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
|
|
526
547
|
/**
|
|
527
548
|
* Remove existing installation directory with Windows-friendly retry logic.
|
|
528
549
|
*/
|
|
@@ -583,16 +604,37 @@ function ensureInstallDir() {
|
|
|
583
604
|
}
|
|
584
605
|
|
|
585
606
|
/**
|
|
586
|
-
* Sync skills.
|
|
607
|
+
* Sync skills directories based on the skills field in openclaw.plugin.json.
|
|
608
|
+
* Reads the manifest to find declared skill paths, resolves them relative to
|
|
609
|
+
* source root, then copies each to the install target.
|
|
587
610
|
*/
|
|
588
|
-
function
|
|
589
|
-
const
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
611
|
+
function syncSkillDirs() {
|
|
612
|
+
const manifestPath = join(SOURCE_DIR, 'openclaw.plugin.json');
|
|
613
|
+
if (!existsSync(manifestPath)) return;
|
|
614
|
+
|
|
615
|
+
let skillsPaths;
|
|
616
|
+
try {
|
|
617
|
+
const manifest = JSON.parse(readFileSync(manifestPath, 'utf-8'));
|
|
618
|
+
skillsPaths = manifest.skills;
|
|
619
|
+
} catch {
|
|
620
|
+
return;
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
if (!skillsPaths || !Array.isArray(skillsPaths)) return;
|
|
624
|
+
|
|
625
|
+
for (const sp of skillsPaths) {
|
|
626
|
+
if (typeof sp !== 'string') continue;
|
|
627
|
+
const source = join(SOURCE_DIR, sp);
|
|
628
|
+
const name = sp.split('/').pop();
|
|
629
|
+
const target = join(INSTALL_DIR, 'skills', name);
|
|
630
|
+
if (!existsSync(source)) {
|
|
631
|
+
console.warn(` ⚠️ skills path not found: ${sp}`);
|
|
632
|
+
continue;
|
|
633
|
+
}
|
|
634
|
+
if (existsSync(target)) rmSync(target, { recursive: true, force: true });
|
|
635
|
+
cpSync(source, target, { recursive: true });
|
|
636
|
+
console.log(` 📄 skills/${name} (from ${sp})`);
|
|
637
|
+
}
|
|
596
638
|
}
|
|
597
639
|
|
|
598
640
|
/**
|
|
@@ -701,6 +743,23 @@ function isWindows() {
|
|
|
701
743
|
return process.platform === 'win32';
|
|
702
744
|
}
|
|
703
745
|
|
|
746
|
+
/**
|
|
747
|
+
* Check if a process is running by PID.
|
|
748
|
+
*/
|
|
749
|
+
function isProcessRunning(pid) {
|
|
750
|
+
try {
|
|
751
|
+
if (isWindows()) {
|
|
752
|
+
execSync(`tasklist /FI "PID eq ${pid}" /FO CSV /NH`, { stdio: 'ignore' });
|
|
753
|
+
return true;
|
|
754
|
+
} else {
|
|
755
|
+
process.kill(pid, 0);
|
|
756
|
+
return true;
|
|
757
|
+
}
|
|
758
|
+
} catch {
|
|
759
|
+
return false;
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
|
|
704
763
|
/**
|
|
705
764
|
* Get temporary directory path (cross-platform).
|
|
706
765
|
*/
|
|
@@ -751,32 +810,57 @@ function restartGatewayWindows() {
|
|
|
751
810
|
}
|
|
752
811
|
} catch { /* no existing processes */ }
|
|
753
812
|
|
|
813
|
+
// Clean stale lock files — prevents ghost gateway false positives
|
|
814
|
+
try {
|
|
815
|
+
const lockDir = join(getTempDir(), 'openclaw');
|
|
816
|
+
if (existsSync(lockDir)) {
|
|
817
|
+
const files = readdirSync(lockDir).filter(f => f.startsWith('gateway.') && f.endsWith('.lock'));
|
|
818
|
+
for (const file of files) {
|
|
819
|
+
const lockPath = join(lockDir, file);
|
|
820
|
+
try {
|
|
821
|
+
const content = readFileSync(lockPath, 'utf-8');
|
|
822
|
+
const pid = parseInt(content.trim());
|
|
823
|
+
// Only remove if PID is not running
|
|
824
|
+
if (!pid || !isProcessRunning(pid)) {
|
|
825
|
+
rmSync(lockPath, { force: true });
|
|
826
|
+
console.log(` Removed stale lock: ${file}`);
|
|
827
|
+
}
|
|
828
|
+
} catch { /* ignore */ }
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
} catch { /* ignore lock cleanup failures */ }
|
|
832
|
+
|
|
754
833
|
// Trigger via schtasks — reliable, avoids CLI busy-port misdetection
|
|
755
834
|
console.log(' Starting gateway via scheduled task...');
|
|
756
835
|
execSync('schtasks /Run /TN "OpenClaw Gateway"', { stdio: 'inherit' });
|
|
757
836
|
|
|
758
|
-
// Wait for gateway to
|
|
759
|
-
const
|
|
837
|
+
// Wait for gateway to be listening on port (同步等待,不异步)
|
|
838
|
+
const port = 18789;
|
|
839
|
+
const deadline = Date.now() + 30000;
|
|
760
840
|
const pollInterval = 1000;
|
|
841
|
+
let gatewayListening = false;
|
|
761
842
|
|
|
762
|
-
|
|
763
|
-
if (Date.now() > deadline) {
|
|
764
|
-
console.warn('⚠️ Gateway started but PD registration not confirmed after 20s.');
|
|
765
|
-
console.log(' Check logs at: ' + logPath);
|
|
766
|
-
return;
|
|
767
|
-
}
|
|
843
|
+
while (Date.now() < deadline) {
|
|
768
844
|
try {
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
845
|
+
const result = execSync(
|
|
846
|
+
`powershell -NoProfile -Command "Get-NetTCPConnection -LocalPort ${port} -State Listen -ErrorAction SilentlyContinue | Measure-Object -Line).Count"`,
|
|
847
|
+
{ encoding: 'utf-8', timeout: 5000 }
|
|
848
|
+
).trim();
|
|
849
|
+
if (parseInt(result) > 0) {
|
|
850
|
+
gatewayListening = true;
|
|
851
|
+
break;
|
|
775
852
|
}
|
|
776
|
-
} catch { /*
|
|
777
|
-
|
|
778
|
-
}
|
|
779
|
-
|
|
853
|
+
} catch { /* port not listening yet */ }
|
|
854
|
+
execSync('timeout /t 1 /nobreak > nul', { shell: true, stdio: 'ignore' });
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
if (!gatewayListening) {
|
|
858
|
+
console.error('\n❌ Gateway did not start on port 18789 within 30s.');
|
|
859
|
+
console.error(' Please restart manually: openclaw gateway start');
|
|
860
|
+
process.exit(1);
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
console.log(' ✅ Gateway is listening on port 18789');
|
|
780
864
|
|
|
781
865
|
} catch (error) {
|
|
782
866
|
console.error(`\n❌ Gateway restart failed: ${error.message}`);
|
|
@@ -890,7 +974,7 @@ function main() {
|
|
|
890
974
|
|
|
891
975
|
console.log('\n📦 Syncing files to OpenClaw...');
|
|
892
976
|
for (const item of SYNC_ITEMS) syncItem(item);
|
|
893
|
-
|
|
977
|
+
syncSkillDirs();
|
|
894
978
|
|
|
895
979
|
injectLocalWorkspacePackages();
|
|
896
980
|
installTargetDependencies();
|
|
@@ -948,6 +1032,7 @@ function main() {
|
|
|
948
1032
|
}
|
|
949
1033
|
|
|
950
1034
|
verifyInstalledFingerprint();
|
|
1035
|
+
updateInstalledPluginVersion(sourceVersion);
|
|
951
1036
|
if (args.dev || args.restart) cleanStaleBackups();
|
|
952
1037
|
|
|
953
1038
|
console.log('\n╔════════════════════════════════════════════════════════════╗');
|
package/src/hooks/prompt.ts
CHANGED
|
@@ -435,7 +435,7 @@ export async function handleBeforePromptBuild(
|
|
|
435
435
|
const contextConfig = loadContextInjectionConfig(workspaceDir);
|
|
436
436
|
|
|
437
437
|
// Minimal mode: heartbeat and subagents skip most context to reduce tokens
|
|
438
|
-
const isMinimalMode = trigger === "heartbeat" || sessionId?.includes(":subagent:") === true;
|
|
438
|
+
const isMinimalMode = trigger === "heartbeat" || trigger === "cron" || sessionId?.includes(":subagent:") === true;
|
|
439
439
|
|
|
440
440
|
const session = sessionId ? getSession(sessionId) : undefined;
|
|
441
441
|
|
|
@@ -700,8 +700,8 @@ The empathy observer subagent handles pain detection independently.
|
|
|
700
700
|
// }
|
|
701
701
|
}
|
|
702
702
|
|
|
703
|
-
// ──── 4. Heartbeat-specific checklist ────
|
|
704
|
-
if (trigger === 'heartbeat') {
|
|
703
|
+
// ──── 4. Heartbeat-specific checklist (also fires for cron-triggered sessions) ────
|
|
704
|
+
if (trigger === 'heartbeat' || trigger === 'cron') {
|
|
705
705
|
// ──── 4a. GFI Time-based Decay ────
|
|
706
706
|
// Apply segmented exponential decay to GFI on each heartbeat
|
|
707
707
|
if (sessionId) {
|