@icaruk/zai-peak-hours 0.0.9 → 0.1.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/dist/config.d.ts +0 -2
- package/dist/config.js +1 -9
- package/dist/index.js +85 -73
- package/dist/peak-hours.js +16 -15
- package/package.json +2 -4
package/dist/config.d.ts
CHANGED
package/dist/config.js
CHANGED
|
@@ -1,11 +1,3 @@
|
|
|
1
1
|
export const DEFAULT_CONFIG = {
|
|
2
|
-
enabled: true
|
|
3
|
-
updateIntervalMinutes: 15 // 15 minutes
|
|
2
|
+
enabled: true
|
|
4
3
|
};
|
|
5
|
-
export function getPluginConfig(config) {
|
|
6
|
-
const userConfig = config?.peakHours || {};
|
|
7
|
-
return {
|
|
8
|
-
enabled: userConfig.enabled !== undefined ? userConfig.enabled : DEFAULT_CONFIG.enabled,
|
|
9
|
-
updateIntervalMinutes: userConfig.updateIntervalMinutes !== undefined ? userConfig.updateIntervalMinutes : DEFAULT_CONFIG.updateIntervalMinutes
|
|
10
|
-
};
|
|
11
|
-
}
|
package/dist/index.js
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
|
-
import { tool } from '@opencode-ai/plugin';
|
|
2
1
|
import { getPeakHoursStatus, formatPeakHoursMessage } from './peak-hours';
|
|
3
2
|
import { DEFAULT_CONFIG } from './config';
|
|
4
3
|
import * as fs from 'node:fs';
|
|
5
4
|
import * as path from 'node:path';
|
|
6
|
-
let timerId = null;
|
|
7
|
-
let configCache = null;
|
|
8
5
|
function getConfigPath() {
|
|
9
6
|
const configDir = process.env.XDG_CONFIG_HOME
|
|
10
7
|
? path.join(process.env.XDG_CONFIG_HOME, 'opencode')
|
|
@@ -12,102 +9,117 @@ function getConfigPath() {
|
|
|
12
9
|
return path.join(configDir, 'peak-hours.json');
|
|
13
10
|
}
|
|
14
11
|
function loadConfig() {
|
|
15
|
-
if (configCache) {
|
|
16
|
-
return configCache;
|
|
17
|
-
}
|
|
18
12
|
const configPath = getConfigPath();
|
|
19
13
|
if (fs.existsSync(configPath)) {
|
|
20
14
|
try {
|
|
21
15
|
const configContent = fs.readFileSync(configPath, 'utf-8');
|
|
22
16
|
const userConfig = JSON.parse(configContent);
|
|
23
|
-
|
|
24
|
-
enabled: userConfig.enabled !== undefined ? userConfig.enabled : DEFAULT_CONFIG.enabled
|
|
25
|
-
updateIntervalMinutes: userConfig.updateIntervalMinutes !== undefined ? userConfig.updateIntervalMinutes : DEFAULT_CONFIG.updateIntervalMinutes
|
|
17
|
+
return {
|
|
18
|
+
enabled: userConfig.enabled !== undefined ? userConfig.enabled : DEFAULT_CONFIG.enabled
|
|
26
19
|
};
|
|
27
|
-
return configCache;
|
|
28
20
|
}
|
|
29
21
|
catch (error) {
|
|
30
22
|
console.error('Error loading peak-hours config:', error);
|
|
31
23
|
}
|
|
32
24
|
}
|
|
33
|
-
|
|
34
|
-
|
|
25
|
+
return DEFAULT_CONFIG;
|
|
26
|
+
}
|
|
27
|
+
function renderCommandHeading(title) {
|
|
28
|
+
return `${title}\n${'='.repeat(title.length)}`;
|
|
29
|
+
}
|
|
30
|
+
function renderStatusReport(status, config) {
|
|
31
|
+
const currentTime = new Date().toISOString();
|
|
32
|
+
const lines = [
|
|
33
|
+
renderCommandHeading('Peak Hours Status'),
|
|
34
|
+
'',
|
|
35
|
+
'Configuration:',
|
|
36
|
+
`- enabled: ${config.enabled}`,
|
|
37
|
+
'',
|
|
38
|
+
'Current Status:',
|
|
39
|
+
`- current_time: ${currentTime}`,
|
|
40
|
+
`- in_peak_hours: ${status.inPeakHours}`,
|
|
41
|
+
`- transition: ${status.transitionType}`,
|
|
42
|
+
`- time_until_${status.transitionType}: ${status.timeUntilTransition}`,
|
|
43
|
+
'',
|
|
44
|
+
'Peak Hours (UTC+8):',
|
|
45
|
+
`- start: 14:00`,
|
|
46
|
+
`- end: 18:00`
|
|
47
|
+
];
|
|
48
|
+
return lines.join('\n');
|
|
35
49
|
}
|
|
36
50
|
export const PeakHours = async ({ client }) => {
|
|
37
51
|
const config = loadConfig();
|
|
52
|
+
const typedClient = client;
|
|
53
|
+
async function injectRawOutput(sessionID, output) {
|
|
54
|
+
try {
|
|
55
|
+
await typedClient.session.prompt({
|
|
56
|
+
path: { id: sessionID },
|
|
57
|
+
body: {
|
|
58
|
+
noReply: true,
|
|
59
|
+
parts: [{ type: 'text', text: output, ignored: true }]
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
catch (err) {
|
|
64
|
+
console.error('Failed to inject output:', err);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
async function handlePeakHoursCommand(sessionID) {
|
|
68
|
+
const status = getPeakHoursStatus();
|
|
69
|
+
const output = formatPeakHoursMessage(status);
|
|
70
|
+
await injectRawOutput(sessionID, output);
|
|
71
|
+
handled();
|
|
72
|
+
}
|
|
73
|
+
async function handlePeakHoursStatusCommand(sessionID) {
|
|
74
|
+
const status = getPeakHoursStatus();
|
|
75
|
+
const output = renderStatusReport(status, config);
|
|
76
|
+
await injectRawOutput(sessionID, output);
|
|
77
|
+
handled();
|
|
78
|
+
}
|
|
38
79
|
return {
|
|
39
|
-
|
|
80
|
+
config: async (input) => {
|
|
81
|
+
input.output.command = {
|
|
82
|
+
peak_hours: {
|
|
83
|
+
template: '',
|
|
84
|
+
description: 'Display current z.ai peak hours status and time until next transition'
|
|
85
|
+
},
|
|
86
|
+
peak_hours_status: {
|
|
87
|
+
template: '',
|
|
88
|
+
description: 'Display peak hours plugin diagnostics and configuration status'
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
},
|
|
92
|
+
'tui.command.execute': async (input) => {
|
|
93
|
+
const command = input.command;
|
|
94
|
+
const sessionID = input.sessionID;
|
|
40
95
|
if (!config.enabled) {
|
|
96
|
+
await injectRawOutput(sessionID, 'Peak Hours plugin is disabled');
|
|
41
97
|
return;
|
|
42
98
|
}
|
|
43
|
-
if (
|
|
44
|
-
|
|
45
|
-
const message = formatPeakHoursMessage(status);
|
|
46
|
-
await client.tui.showToast({
|
|
47
|
-
body: {
|
|
48
|
-
message,
|
|
49
|
-
variant: status.inPeakHours ? 'warning' : 'info'
|
|
50
|
-
}
|
|
51
|
-
});
|
|
99
|
+
if (command === 'peak_hours') {
|
|
100
|
+
await handlePeakHoursCommand(sessionID);
|
|
52
101
|
}
|
|
53
|
-
else if (
|
|
54
|
-
|
|
55
|
-
const status = getPeakHoursStatus();
|
|
56
|
-
const currentTime = new Date().toISOString();
|
|
57
|
-
const diagnostics = `=== Peak Hours Plugin Diagnostics ===
|
|
58
|
-
Plugin enabled: ${config.enabled}
|
|
59
|
-
Update interval: ${config.updateIntervalMinutes} minutes
|
|
60
|
-
Current time: ${currentTime}
|
|
61
|
-
In peak hours: ${status.inPeakHours}
|
|
62
|
-
Time until ${status.transitionType}: ${status.timeUntilTransition}
|
|
63
|
-
===================================`;
|
|
64
|
-
await client.tui.showToast({
|
|
65
|
-
body: {
|
|
66
|
-
message: diagnostics,
|
|
67
|
-
variant: 'info'
|
|
68
|
-
}
|
|
69
|
-
});
|
|
102
|
+
else if (command === 'peak_hours_status') {
|
|
103
|
+
await handlePeakHoursStatusCommand(sessionID);
|
|
70
104
|
}
|
|
71
105
|
},
|
|
72
|
-
'session.created': async () => {
|
|
106
|
+
'session.created': async (input) => {
|
|
73
107
|
if (!config.enabled) {
|
|
74
108
|
return;
|
|
75
109
|
}
|
|
76
110
|
const status = getPeakHoursStatus();
|
|
77
111
|
const message = formatPeakHoursMessage(status);
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
async execute(_args, context) {
|
|
90
|
-
const status = getPeakHoursStatus();
|
|
91
|
-
const message = formatPeakHoursMessage(status);
|
|
92
|
-
return `Peak Hours Status:\n${message}\n\nIn peak hours: ${status.inPeakHours}\nTime until ${status.transitionType}: ${status.timeUntilTransition}`;
|
|
93
|
-
}
|
|
94
|
-
}),
|
|
95
|
-
'peak_hours_status': tool({
|
|
96
|
-
description: 'Display peak hours plugin diagnostics and configuration status',
|
|
97
|
-
args: {},
|
|
98
|
-
async execute(_args, context) {
|
|
99
|
-
const config = loadConfig();
|
|
100
|
-
const status = getPeakHoursStatus();
|
|
101
|
-
const currentTime = new Date().toISOString();
|
|
102
|
-
return `=== Peak Hours Plugin Diagnostics ===
|
|
103
|
-
Plugin enabled: ${config.enabled}
|
|
104
|
-
Update interval: ${config.updateIntervalMinutes} minutes
|
|
105
|
-
Current time: ${currentTime}
|
|
106
|
-
In peak hours: ${status.inPeakHours}
|
|
107
|
-
Time until ${status.transitionType}: ${status.timeUntilTransition}
|
|
108
|
-
====================================`;
|
|
109
|
-
}
|
|
110
|
-
})
|
|
112
|
+
try {
|
|
113
|
+
await typedClient.tui.showToast({
|
|
114
|
+
body: {
|
|
115
|
+
message,
|
|
116
|
+
variant: status.inPeakHours ? 'warning' : 'info'
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
catch (err) {
|
|
121
|
+
console.error('Failed to show toast:', err);
|
|
122
|
+
}
|
|
111
123
|
}
|
|
112
124
|
};
|
|
113
125
|
};
|
package/dist/peak-hours.js
CHANGED
|
@@ -1,32 +1,33 @@
|
|
|
1
|
-
import dayjs from 'dayjs';
|
|
2
|
-
import utc from 'dayjs/plugin/utc.js';
|
|
3
|
-
import timezone from 'dayjs/plugin/timezone.js';
|
|
4
|
-
dayjs.extend(utc);
|
|
5
|
-
dayjs.extend(timezone);
|
|
6
1
|
export function getPeakHoursStatus() {
|
|
7
2
|
const peakHoursStart = 14;
|
|
8
3
|
const peakHoursEnd = 18;
|
|
9
|
-
|
|
10
|
-
const
|
|
4
|
+
// Calcular hora actual en UTC+8 (China timezone)
|
|
5
|
+
const now = new Date();
|
|
6
|
+
const utcMs = now.getTime() + now.getTimezoneOffset() * 60000;
|
|
7
|
+
const chinaTime = new Date(utcMs + 8 * 3600000);
|
|
8
|
+
const currentHour = chinaTime.getHours();
|
|
11
9
|
let inPeakHours;
|
|
12
10
|
let transitionTime;
|
|
13
11
|
let transitionType;
|
|
14
12
|
if (currentHour >= peakHoursStart && currentHour < peakHoursEnd) {
|
|
15
13
|
inPeakHours = true;
|
|
16
14
|
transitionType = 'end';
|
|
17
|
-
transitionTime =
|
|
15
|
+
transitionTime = new Date(chinaTime);
|
|
16
|
+
transitionTime.setHours(peakHoursEnd, 0, 0, 0);
|
|
18
17
|
}
|
|
19
18
|
else {
|
|
20
19
|
inPeakHours = false;
|
|
21
20
|
transitionType = 'start';
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
21
|
+
let transitionDay = new Date(chinaTime);
|
|
22
|
+
if (currentHour >= peakHoursEnd) {
|
|
23
|
+
transitionDay.setDate(transitionDay.getDate() + 1);
|
|
24
|
+
}
|
|
25
|
+
transitionDay.setHours(peakHoursStart, 0, 0, 0);
|
|
26
|
+
transitionTime = transitionDay;
|
|
26
27
|
}
|
|
27
|
-
const
|
|
28
|
-
const hours = Math.floor(
|
|
29
|
-
const minutes = Math.floor((
|
|
28
|
+
const diffMs = transitionTime.getTime() - chinaTime.getTime();
|
|
29
|
+
const hours = Math.floor(diffMs / (1000 * 60 * 60));
|
|
30
|
+
const minutes = Math.floor((diffMs % (1000 * 60 * 60)) / (1000 * 60));
|
|
30
31
|
let timeUntilTransition;
|
|
31
32
|
if (hours > 0 && minutes > 0) {
|
|
32
33
|
timeUntilTransition = `${hours} hours ${minutes} minutes`;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@icaruk/zai-peak-hours",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "OpenCode plugin to display z.ai peak hours information with automatic timezone detection",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -26,9 +26,7 @@
|
|
|
26
26
|
"author": "Icaruk",
|
|
27
27
|
"license": "MIT",
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@opencode-ai/plugin": "^1.4.
|
|
30
|
-
"@opencode-ai/sdk": "^1.4.3",
|
|
31
|
-
"dayjs": "^1.11.10"
|
|
29
|
+
"@opencode-ai/plugin": "^1.4.3"
|
|
32
30
|
},
|
|
33
31
|
"devDependencies": {
|
|
34
32
|
"@types/node": "^20.0.0",
|