stella-timeline-plugin 2.0.5 → 2.0.7
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/README.md +1 -1
- package/README_ZH.md +1 -1
- package/dist/src/plugin_metadata.js +1 -1
- package/dist/src/runtime/openclaw_timeline_runtime.js +166 -89
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/scripts/release.mjs +25 -0
package/README.md
CHANGED
package/README_ZH.md
CHANGED
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.TIMELINE_SKILL_PATHS = exports.TIMELINE_TOOL_NAMES = exports.TIMELINE_PLUGIN_DESCRIPTION = exports.TIMELINE_PLUGIN_VERSION = exports.TIMELINE_PLUGIN_NAME = exports.TIMELINE_PLUGIN_ID = void 0;
|
|
4
4
|
exports.TIMELINE_PLUGIN_ID = 'stella-timeline-plugin';
|
|
5
5
|
exports.TIMELINE_PLUGIN_NAME = 'Stella Timeline Plugin';
|
|
6
|
-
exports.TIMELINE_PLUGIN_VERSION = '2.0.
|
|
6
|
+
exports.TIMELINE_PLUGIN_VERSION = '2.0.7';
|
|
7
7
|
exports.TIMELINE_PLUGIN_DESCRIPTION = 'OpenClaw timeline runtime with canonical timeline_resolve, LLM-based temporal reasoning, and guarded append-only writes.';
|
|
8
8
|
exports.TIMELINE_TOOL_NAMES = ['timeline_resolve'];
|
|
9
9
|
exports.TIMELINE_SKILL_PATHS = ['skills/timeline'];
|
|
@@ -33,12 +33,23 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.setOpenClawPluginRuntimeModuleLoaderForTests = setOpenClawPluginRuntimeModuleLoaderForTests;
|
|
37
|
+
exports.resetOpenClawPluginRuntimeModuleLoaderForTests = resetOpenClawPluginRuntimeModuleLoaderForTests;
|
|
36
38
|
exports.makeOpenClawTimelineResolveToolFactory = makeOpenClawTimelineResolveToolFactory;
|
|
37
39
|
const fs = __importStar(require("fs"));
|
|
38
40
|
const path = __importStar(require("path"));
|
|
39
41
|
const conversation_context_1 = require("./conversation_context");
|
|
40
42
|
const time_utils_1 = require("../lib/time-utils");
|
|
41
43
|
const timeline_resolve_1 = require("../tools/timeline_resolve");
|
|
44
|
+
let openClawPluginRuntimeModuleLoader = () => {
|
|
45
|
+
try {
|
|
46
|
+
return require('openclaw/plugin-sdk/runtime');
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
let cachedLateBoundGatewaySubagentRuntime;
|
|
42
53
|
function readString(value) {
|
|
43
54
|
return typeof value === 'string' && value.trim() ? value.trim() : undefined;
|
|
44
55
|
}
|
|
@@ -67,6 +78,78 @@ function wrapToolPayload(payload) {
|
|
|
67
78
|
details: payload,
|
|
68
79
|
};
|
|
69
80
|
}
|
|
81
|
+
function isSubagentRuntimeAvailable(runtime) {
|
|
82
|
+
return Boolean(runtime
|
|
83
|
+
&& typeof runtime.run === 'function'
|
|
84
|
+
&& typeof runtime.waitForRun === 'function'
|
|
85
|
+
&& typeof runtime.getSessionMessages === 'function');
|
|
86
|
+
}
|
|
87
|
+
function isUnavailableSubagentRuntimeError(error) {
|
|
88
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
89
|
+
return message.includes('Plugin runtime subagent methods are only available during a gateway request.');
|
|
90
|
+
}
|
|
91
|
+
function getLateBoundGatewaySubagentRuntime(pluginApi) {
|
|
92
|
+
if (cachedLateBoundGatewaySubagentRuntime !== undefined) {
|
|
93
|
+
return cachedLateBoundGatewaySubagentRuntime || undefined;
|
|
94
|
+
}
|
|
95
|
+
const runtimeModule = openClawPluginRuntimeModuleLoader();
|
|
96
|
+
const lateBoundRuntime = runtimeModule?.createPluginRuntime?.({
|
|
97
|
+
allowGatewaySubagentBinding: true,
|
|
98
|
+
});
|
|
99
|
+
const lateBoundSubagent = lateBoundRuntime?.subagent;
|
|
100
|
+
const subagentRuntime = isSubagentRuntimeAvailable(lateBoundSubagent)
|
|
101
|
+
? lateBoundSubagent
|
|
102
|
+
: undefined;
|
|
103
|
+
if (!subagentRuntime) {
|
|
104
|
+
pluginApi.logger?.debug?.('timeline late-bound gateway subagent runtime unavailable');
|
|
105
|
+
}
|
|
106
|
+
cachedLateBoundGatewaySubagentRuntime = subagentRuntime ?? null;
|
|
107
|
+
return subagentRuntime;
|
|
108
|
+
}
|
|
109
|
+
async function withPreferredSubagentRuntime(pluginApi, purpose, execute) {
|
|
110
|
+
const injectedSubagent = pluginApi.runtime?.subagent;
|
|
111
|
+
const injectedRuntime = isSubagentRuntimeAvailable(injectedSubagent)
|
|
112
|
+
? injectedSubagent
|
|
113
|
+
: undefined;
|
|
114
|
+
let injectedError;
|
|
115
|
+
if (injectedRuntime) {
|
|
116
|
+
try {
|
|
117
|
+
return await execute(injectedRuntime);
|
|
118
|
+
}
|
|
119
|
+
catch (error) {
|
|
120
|
+
injectedError = error;
|
|
121
|
+
if (!isUnavailableSubagentRuntimeError(error)) {
|
|
122
|
+
throw error;
|
|
123
|
+
}
|
|
124
|
+
pluginApi.logger?.debug?.(`timeline ${purpose} retrying with late-bound gateway subagent runtime`, {
|
|
125
|
+
error: error instanceof Error ? error.message : String(error),
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
const lateBoundRuntime = getLateBoundGatewaySubagentRuntime(pluginApi);
|
|
130
|
+
if (lateBoundRuntime && lateBoundRuntime !== injectedRuntime) {
|
|
131
|
+
return execute(lateBoundRuntime);
|
|
132
|
+
}
|
|
133
|
+
if (injectedError) {
|
|
134
|
+
throw injectedError;
|
|
135
|
+
}
|
|
136
|
+
throw new Error(`${purpose} dependency missing`);
|
|
137
|
+
}
|
|
138
|
+
function setOpenClawPluginRuntimeModuleLoaderForTests(loader) {
|
|
139
|
+
openClawPluginRuntimeModuleLoader = loader;
|
|
140
|
+
cachedLateBoundGatewaySubagentRuntime = undefined;
|
|
141
|
+
}
|
|
142
|
+
function resetOpenClawPluginRuntimeModuleLoaderForTests() {
|
|
143
|
+
openClawPluginRuntimeModuleLoader = () => {
|
|
144
|
+
try {
|
|
145
|
+
return require('openclaw/plugin-sdk/runtime');
|
|
146
|
+
}
|
|
147
|
+
catch {
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
cachedLateBoundGatewaySubagentRuntime = undefined;
|
|
152
|
+
}
|
|
70
153
|
function resolveWorkspaceDir(pluginApi, toolContext) {
|
|
71
154
|
if (toolContext.workspaceDir)
|
|
72
155
|
return toolContext.workspaceDir;
|
|
@@ -616,61 +699,59 @@ function buildFallbackReasonerOutput(collector, error) {
|
|
|
616
699
|
function createTimelineQueryPlanner(pluginApi, toolContext, runtimeConfig) {
|
|
617
700
|
return async (input, anchor) => {
|
|
618
701
|
try {
|
|
619
|
-
const subagentRuntime = pluginApi.runtime?.subagent;
|
|
620
|
-
if (!subagentRuntime?.run || !subagentRuntime.waitForRun || !subagentRuntime.getSessionMessages) {
|
|
621
|
-
throw new Error('Timeline query planner dependency missing');
|
|
622
|
-
}
|
|
623
702
|
if (!String(input.query || '').trim()) {
|
|
624
703
|
throw new Error('Timeline query planner dependency missing query');
|
|
625
704
|
}
|
|
626
705
|
const requestId = makePlannerRequestId();
|
|
627
706
|
const baseSessionKey = toolContext.sessionKey || `plugin:${runtimeConfig.reasonerSessionPrefix}`;
|
|
628
707
|
const plannerSessionKey = `${baseSessionKey}:${runtimeConfig.reasonerSessionPrefix}:planner:${requestId}`;
|
|
629
|
-
|
|
630
|
-
const runResult = await subagentRuntime.run({
|
|
631
|
-
sessionKey: plannerSessionKey,
|
|
632
|
-
message: buildTimelineQueryPlannerMessage(input, anchor, requestId),
|
|
633
|
-
extraSystemPrompt: buildTimelineQueryPlannerSystemPrompt(),
|
|
634
|
-
deliver: false,
|
|
635
|
-
idempotencyKey: requestId,
|
|
636
|
-
});
|
|
637
|
-
const waitResult = await subagentRuntime.waitForRun({
|
|
638
|
-
runId: runResult.runId,
|
|
639
|
-
timeoutMs: runtimeConfig.reasonerTimeoutMs,
|
|
640
|
-
});
|
|
641
|
-
if (waitResult.status === 'timeout') {
|
|
642
|
-
throw new Error('Timeline query planner returned no decision');
|
|
643
|
-
}
|
|
644
|
-
if (waitResult.status === 'error') {
|
|
645
|
-
throw new Error(waitResult.error || 'Timeline query planner returned no decision');
|
|
646
|
-
}
|
|
647
|
-
const session = await subagentRuntime.getSessionMessages({
|
|
648
|
-
sessionKey: plannerSessionKey,
|
|
649
|
-
limit: runtimeConfig.reasonerMessageLimit,
|
|
650
|
-
});
|
|
651
|
-
const jsonText = extractJsonObjectFromMessages(session.messages || [], 'Timeline query planner', requestId);
|
|
652
|
-
const parsed = JSON.parse(jsonText);
|
|
653
|
-
if (parsed.request_id && parsed.request_id !== requestId) {
|
|
654
|
-
throw new Error('Timeline query planner returned mismatched request_id');
|
|
655
|
-
}
|
|
656
|
-
if (!['now', 'past_point', 'past_range'].includes(parsed.target_time_range)) {
|
|
657
|
-
throw new Error('Timeline query planner returned an invalid target_time_range');
|
|
658
|
-
}
|
|
659
|
-
return parsed;
|
|
660
|
-
}
|
|
661
|
-
finally {
|
|
708
|
+
return await withPreferredSubagentRuntime(pluginApi, 'Timeline query planner', async (subagentRuntime) => {
|
|
662
709
|
try {
|
|
663
|
-
await subagentRuntime.
|
|
710
|
+
const runResult = await subagentRuntime.run({
|
|
664
711
|
sessionKey: plannerSessionKey,
|
|
665
|
-
|
|
712
|
+
message: buildTimelineQueryPlannerMessage(input, anchor, requestId),
|
|
713
|
+
extraSystemPrompt: buildTimelineQueryPlannerSystemPrompt(),
|
|
714
|
+
deliver: false,
|
|
715
|
+
idempotencyKey: requestId,
|
|
666
716
|
});
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
717
|
+
const waitResult = await subagentRuntime.waitForRun({
|
|
718
|
+
runId: runResult.runId,
|
|
719
|
+
timeoutMs: runtimeConfig.reasonerTimeoutMs,
|
|
720
|
+
});
|
|
721
|
+
if (waitResult.status === 'timeout') {
|
|
722
|
+
throw new Error('Timeline query planner returned no decision');
|
|
723
|
+
}
|
|
724
|
+
if (waitResult.status === 'error') {
|
|
725
|
+
throw new Error(waitResult.error || 'Timeline query planner returned no decision');
|
|
726
|
+
}
|
|
727
|
+
const session = await subagentRuntime.getSessionMessages({
|
|
728
|
+
sessionKey: plannerSessionKey,
|
|
729
|
+
limit: runtimeConfig.reasonerMessageLimit,
|
|
671
730
|
});
|
|
731
|
+
const jsonText = extractJsonObjectFromMessages(session.messages || [], 'Timeline query planner', requestId);
|
|
732
|
+
const parsed = JSON.parse(jsonText);
|
|
733
|
+
if (parsed.request_id && parsed.request_id !== requestId) {
|
|
734
|
+
throw new Error('Timeline query planner returned mismatched request_id');
|
|
735
|
+
}
|
|
736
|
+
if (!['now', 'past_point', 'past_range'].includes(parsed.target_time_range)) {
|
|
737
|
+
throw new Error('Timeline query planner returned an invalid target_time_range');
|
|
738
|
+
}
|
|
739
|
+
return parsed;
|
|
672
740
|
}
|
|
673
|
-
|
|
741
|
+
finally {
|
|
742
|
+
try {
|
|
743
|
+
await subagentRuntime.deleteSession?.({
|
|
744
|
+
sessionKey: plannerSessionKey,
|
|
745
|
+
deleteTranscript: true,
|
|
746
|
+
});
|
|
747
|
+
}
|
|
748
|
+
catch (error) {
|
|
749
|
+
pluginApi.logger?.debug?.('timeline query planner session cleanup skipped', {
|
|
750
|
+
error: error instanceof Error ? error.message : String(error),
|
|
751
|
+
});
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
});
|
|
674
755
|
}
|
|
675
756
|
catch (error) {
|
|
676
757
|
pluginApi.logger?.warn?.('timeline query planner fallback engaged', {
|
|
@@ -751,50 +832,48 @@ function buildTimelineReasonerMessage(collector) {
|
|
|
751
832
|
function createSubagentReasoner(pluginApi, toolContext, runtimeConfig) {
|
|
752
833
|
return async (collector) => {
|
|
753
834
|
try {
|
|
754
|
-
const subagentRuntime = pluginApi.runtime?.subagent;
|
|
755
|
-
if (!subagentRuntime?.run || !subagentRuntime.waitForRun || !subagentRuntime.getSessionMessages) {
|
|
756
|
-
throw new Error('Timeline reasoner dependency missing');
|
|
757
|
-
}
|
|
758
835
|
const baseSessionKey = toolContext.sessionKey || `plugin:${runtimeConfig.reasonerSessionPrefix}`;
|
|
759
836
|
const reasonerSessionKey = `${baseSessionKey}:${runtimeConfig.reasonerSessionPrefix}:${collector.request_id}`;
|
|
760
|
-
|
|
761
|
-
const runResult = await subagentRuntime.run({
|
|
762
|
-
sessionKey: reasonerSessionKey,
|
|
763
|
-
message: buildTimelineReasonerMessage(collector),
|
|
764
|
-
extraSystemPrompt: buildTimelineReasonerSystemPrompt(),
|
|
765
|
-
deliver: false,
|
|
766
|
-
idempotencyKey: collector.request_id,
|
|
767
|
-
});
|
|
768
|
-
const waitResult = await subagentRuntime.waitForRun({
|
|
769
|
-
runId: runResult.runId,
|
|
770
|
-
timeoutMs: runtimeConfig.reasonerTimeoutMs,
|
|
771
|
-
});
|
|
772
|
-
if (waitResult.status === 'timeout') {
|
|
773
|
-
throw new Error('Timeline reasoner returned no decision');
|
|
774
|
-
}
|
|
775
|
-
if (waitResult.status === 'error') {
|
|
776
|
-
throw new Error(waitResult.error || 'Timeline reasoner returned no decision');
|
|
777
|
-
}
|
|
778
|
-
const session = await subagentRuntime.getSessionMessages({
|
|
779
|
-
sessionKey: reasonerSessionKey,
|
|
780
|
-
limit: runtimeConfig.reasonerMessageLimit,
|
|
781
|
-
});
|
|
782
|
-
const jsonText = extractJsonObjectFromMessages(session.messages || [], 'Timeline reasoner', collector.request_id);
|
|
783
|
-
return JSON.parse(jsonText);
|
|
784
|
-
}
|
|
785
|
-
finally {
|
|
837
|
+
return await withPreferredSubagentRuntime(pluginApi, 'Timeline reasoner', async (subagentRuntime) => {
|
|
786
838
|
try {
|
|
787
|
-
await subagentRuntime.
|
|
839
|
+
const runResult = await subagentRuntime.run({
|
|
788
840
|
sessionKey: reasonerSessionKey,
|
|
789
|
-
|
|
841
|
+
message: buildTimelineReasonerMessage(collector),
|
|
842
|
+
extraSystemPrompt: buildTimelineReasonerSystemPrompt(),
|
|
843
|
+
deliver: false,
|
|
844
|
+
idempotencyKey: collector.request_id,
|
|
790
845
|
});
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
error: error instanceof Error ? error.message : String(error),
|
|
846
|
+
const waitResult = await subagentRuntime.waitForRun({
|
|
847
|
+
runId: runResult.runId,
|
|
848
|
+
timeoutMs: runtimeConfig.reasonerTimeoutMs,
|
|
795
849
|
});
|
|
850
|
+
if (waitResult.status === 'timeout') {
|
|
851
|
+
throw new Error('Timeline reasoner returned no decision');
|
|
852
|
+
}
|
|
853
|
+
if (waitResult.status === 'error') {
|
|
854
|
+
throw new Error(waitResult.error || 'Timeline reasoner returned no decision');
|
|
855
|
+
}
|
|
856
|
+
const session = await subagentRuntime.getSessionMessages({
|
|
857
|
+
sessionKey: reasonerSessionKey,
|
|
858
|
+
limit: runtimeConfig.reasonerMessageLimit,
|
|
859
|
+
});
|
|
860
|
+
const jsonText = extractJsonObjectFromMessages(session.messages || [], 'Timeline reasoner', collector.request_id);
|
|
861
|
+
return JSON.parse(jsonText);
|
|
796
862
|
}
|
|
797
|
-
|
|
863
|
+
finally {
|
|
864
|
+
try {
|
|
865
|
+
await subagentRuntime.deleteSession?.({
|
|
866
|
+
sessionKey: reasonerSessionKey,
|
|
867
|
+
deleteTranscript: true,
|
|
868
|
+
});
|
|
869
|
+
}
|
|
870
|
+
catch (error) {
|
|
871
|
+
pluginApi.logger?.debug?.('timeline reasoner session cleanup skipped', {
|
|
872
|
+
error: error instanceof Error ? error.message : String(error),
|
|
873
|
+
});
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
});
|
|
798
877
|
}
|
|
799
878
|
catch (error) {
|
|
800
879
|
pluginApi.logger?.warn?.('timeline reasoner fallback engaged', {
|
|
@@ -819,14 +898,13 @@ function createTimelineResolveDependencies(pluginApi, toolContext) {
|
|
|
819
898
|
}),
|
|
820
899
|
sessionsHistory: async () => {
|
|
821
900
|
const sessionKey = toolContext.sessionKey;
|
|
822
|
-
|
|
823
|
-
if (!sessionKey || !getSessionMessages)
|
|
901
|
+
if (!sessionKey)
|
|
824
902
|
return [];
|
|
825
903
|
try {
|
|
826
|
-
const session = await getSessionMessages({
|
|
904
|
+
const session = await withPreferredSubagentRuntime(pluginApi, 'timeline sessionsHistory', (subagentRuntime) => subagentRuntime.getSessionMessages({
|
|
827
905
|
sessionKey,
|
|
828
906
|
limit: runtimeConfig.sessionHistoryLimit,
|
|
829
|
-
});
|
|
907
|
+
}));
|
|
830
908
|
return normalizeSessionHistory(session.messages || [], runtimeConfig.sessionHistoryLimit);
|
|
831
909
|
}
|
|
832
910
|
catch (error) {
|
|
@@ -838,8 +916,7 @@ function createTimelineResolveDependencies(pluginApi, toolContext) {
|
|
|
838
916
|
},
|
|
839
917
|
conversationContext: async (window, input) => {
|
|
840
918
|
const sessionKey = toolContext.sessionKey;
|
|
841
|
-
|
|
842
|
-
if (!sessionKey || !getSessionMessages) {
|
|
919
|
+
if (!sessionKey) {
|
|
843
920
|
return {
|
|
844
921
|
is_recently_active: false,
|
|
845
922
|
minutes_since_last_turn: null,
|
|
@@ -849,10 +926,10 @@ function createTimelineResolveDependencies(pluginApi, toolContext) {
|
|
|
849
926
|
};
|
|
850
927
|
}
|
|
851
928
|
try {
|
|
852
|
-
const session = await getSessionMessages({
|
|
929
|
+
const session = await withPreferredSubagentRuntime(pluginApi, 'timeline conversationContext', (subagentRuntime) => subagentRuntime.getSessionMessages({
|
|
853
930
|
sessionKey,
|
|
854
931
|
limit: runtimeConfig.sessionHistoryLimit,
|
|
855
|
-
});
|
|
932
|
+
}));
|
|
856
933
|
return (0, conversation_context_1.buildConversationContextFromMessages)(session.messages || [], window.end, input, runtimeConfig.conversationStickinessWindowMinutes, window.query_range);
|
|
857
934
|
}
|
|
858
935
|
catch (error) {
|
package/openclaw.plugin.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "stella-timeline-plugin",
|
|
3
3
|
"name": "Stella Timeline Plugin",
|
|
4
|
-
"version": "2.0.
|
|
4
|
+
"version": "2.0.7",
|
|
5
5
|
"description": "OpenClaw timeline runtime with canonical timeline_resolve, LLM-based temporal reasoning, and guarded append-only writes.",
|
|
6
6
|
"entry": "dist/index.js",
|
|
7
7
|
"skills": [
|
package/package.json
CHANGED
package/scripts/release.mjs
CHANGED
|
@@ -19,6 +19,30 @@ function syncPluginVersion() {
|
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
function syncPluginMetadataVersion() {
|
|
23
|
+
const pkgPath = path.join(repoRoot, 'package.json');
|
|
24
|
+
const metadataPath = path.join(repoRoot, 'src', 'plugin_metadata.ts');
|
|
25
|
+
|
|
26
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
|
|
27
|
+
const metadataSource = fs.readFileSync(metadataPath, 'utf8');
|
|
28
|
+
const nextVersion = String(pkg.version);
|
|
29
|
+
|
|
30
|
+
const versionDeclRegex = /export const TIMELINE_PLUGIN_VERSION\s*=\s*'[^']*';/;
|
|
31
|
+
// If the regex doesn't match, don't silently proceed with a wrong release.
|
|
32
|
+
if (!versionDeclRegex.test(metadataSource)) {
|
|
33
|
+
throw new Error(`Unable to sync TIMELINE_PLUGIN_VERSION in ${metadataPath}`);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const updatedSource = metadataSource.replace(
|
|
37
|
+
versionDeclRegex,
|
|
38
|
+
`export const TIMELINE_PLUGIN_VERSION = '${nextVersion}';`,
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
if (updatedSource !== metadataSource) {
|
|
42
|
+
fs.writeFileSync(metadataPath, `${updatedSource}\n`, 'utf8');
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
22
46
|
function npmCommand() {
|
|
23
47
|
return process.platform === 'win32' ? 'npm.cmd' : 'npm';
|
|
24
48
|
}
|
|
@@ -59,6 +83,7 @@ function main() {
|
|
|
59
83
|
|
|
60
84
|
// Keep OpenClaw plugin manifest version aligned with the npm package version.
|
|
61
85
|
syncPluginVersion();
|
|
86
|
+
syncPluginMetadataVersion();
|
|
62
87
|
|
|
63
88
|
run(npmCommand(), ['run', 'verify']);
|
|
64
89
|
run(npmCommand(), ['publish', ...publishArgs]);
|