codeksei 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/LICENSE +661 -0
- package/README.en.md +215 -0
- package/README.md +259 -0
- package/bin/codeksei.js +10 -0
- package/bin/cyberboss.js +11 -0
- package/package.json +86 -0
- package/scripts/install-background-tasks.ps1 +135 -0
- package/scripts/open_shared_wechat_thread.sh +94 -0
- package/scripts/open_wechat_thread.sh +117 -0
- package/scripts/shared-common.js +791 -0
- package/scripts/shared-open.js +46 -0
- package/scripts/shared-start.js +41 -0
- package/scripts/shared-status.js +74 -0
- package/scripts/shared-supervisor.js +141 -0
- package/scripts/shared-task-runner.ps1 +87 -0
- package/scripts/shared-watchdog.js +290 -0
- package/scripts/show_shared_status.sh +53 -0
- package/scripts/start_shared_app_server.sh +65 -0
- package/scripts/start_shared_wechat.sh +108 -0
- package/scripts/timeline-screenshot.sh +15 -0
- package/scripts/uninstall-background-tasks.ps1 +23 -0
- package/src/adapters/channel/weixin/account-store.js +135 -0
- package/src/adapters/channel/weixin/api-v2.js +258 -0
- package/src/adapters/channel/weixin/api.js +180 -0
- package/src/adapters/channel/weixin/context-token-store.js +84 -0
- package/src/adapters/channel/weixin/index.js +605 -0
- package/src/adapters/channel/weixin/legacy.js +567 -0
- package/src/adapters/channel/weixin/login-common.js +63 -0
- package/src/adapters/channel/weixin/login-legacy.js +124 -0
- package/src/adapters/channel/weixin/login-v2.js +186 -0
- package/src/adapters/channel/weixin/media-mime.js +22 -0
- package/src/adapters/channel/weixin/media-receive.js +370 -0
- package/src/adapters/channel/weixin/media-send.js +331 -0
- package/src/adapters/channel/weixin/message-utils-v2.js +282 -0
- package/src/adapters/channel/weixin/message-utils.js +199 -0
- package/src/adapters/channel/weixin/protocol.js +77 -0
- package/src/adapters/channel/weixin/redact.js +41 -0
- package/src/adapters/channel/weixin/reminder-queue-store.js +101 -0
- package/src/adapters/channel/weixin/sync-buffer-store.js +35 -0
- package/src/adapters/runtime/codex/events.js +252 -0
- package/src/adapters/runtime/codex/index.js +502 -0
- package/src/adapters/runtime/codex/message-utils.js +141 -0
- package/src/adapters/runtime/codex/model-catalog.js +106 -0
- package/src/adapters/runtime/codex/protocol-leak-monitor.js +75 -0
- package/src/adapters/runtime/codex/rpc-client.js +443 -0
- package/src/adapters/runtime/codex/session-store.js +376 -0
- package/src/app/channel-send-file-cli.js +57 -0
- package/src/app/diary-write-cli.js +620 -0
- package/src/app/note-auto-cli.js +201 -0
- package/src/app/note-sync-cli.js +130 -0
- package/src/app/project-radar-cli.js +165 -0
- package/src/app/reminder-write-cli.js +210 -0
- package/src/app/review-cli.js +134 -0
- package/src/app/system-checkin-poller.js +100 -0
- package/src/app/system-send-cli.js +129 -0
- package/src/app/timeline-event-cli.js +273 -0
- package/src/app/timeline-screenshot-cli.js +109 -0
- package/src/core/app.js +1810 -0
- package/src/core/branding.js +167 -0
- package/src/core/command-registry.js +609 -0
- package/src/core/config.js +84 -0
- package/src/core/default-targets.js +163 -0
- package/src/core/durable-note-schema.js +325 -0
- package/src/core/instructions-template.js +31 -0
- package/src/core/note-sync.js +433 -0
- package/src/core/project-radar.js +402 -0
- package/src/core/review-semantic.js +524 -0
- package/src/core/review.js +1081 -0
- package/src/core/shared-bridge-heartbeat.js +140 -0
- package/src/core/stream-delivery.js +990 -0
- package/src/core/system-message-dispatcher.js +68 -0
- package/src/core/system-message-queue-store.js +128 -0
- package/src/core/thread-state-store.js +135 -0
- package/src/core/timeline-screenshot-queue-store.js +134 -0
- package/src/core/workspace-alias.js +163 -0
- package/src/core/workspace-bootstrap.js +338 -0
- package/src/index.js +270 -0
- package/src/integrations/timeline/index.js +191 -0
- package/templates/weixin-instructions.md +53 -0
- package/templates/weixin-operations.md +69 -0
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
const { loadPersistedContextTokens } = require("../adapters/channel/weixin/context-token-store");
|
|
2
|
+
|
|
3
|
+
function resolvePreferredSenderId({
|
|
4
|
+
config,
|
|
5
|
+
accountId,
|
|
6
|
+
explicitUser = "",
|
|
7
|
+
sessionStore = null,
|
|
8
|
+
}) {
|
|
9
|
+
const normalizedExplicitUser = normalizeText(explicitUser);
|
|
10
|
+
if (normalizedExplicitUser) {
|
|
11
|
+
return normalizedExplicitUser;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const configuredUsers = Array.isArray(config?.allowedUserIds)
|
|
15
|
+
? config.allowedUserIds.map((value) => normalizeText(value)).filter(Boolean)
|
|
16
|
+
: [];
|
|
17
|
+
if (configuredUsers.length) {
|
|
18
|
+
return configuredUsers[0];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const bindingCandidates = collectBindingSenderIds({ config, accountId, sessionStore });
|
|
22
|
+
if (bindingCandidates.length === 1) {
|
|
23
|
+
return bindingCandidates[0];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const persistedUserIds = Object.keys(loadPersistedContextTokens(config, accountId) || {})
|
|
27
|
+
.map((value) => normalizeText(value))
|
|
28
|
+
.filter(Boolean);
|
|
29
|
+
if (persistedUserIds.length === 1) {
|
|
30
|
+
return persistedUserIds[0];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return "";
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function resolvePreferredWorkspaceRoot({
|
|
37
|
+
config,
|
|
38
|
+
accountId,
|
|
39
|
+
senderId = "",
|
|
40
|
+
explicitWorkspace = "",
|
|
41
|
+
sessionStore = null,
|
|
42
|
+
}) {
|
|
43
|
+
const normalizedExplicitWorkspace = normalizeText(explicitWorkspace);
|
|
44
|
+
if (normalizedExplicitWorkspace) {
|
|
45
|
+
return normalizedExplicitWorkspace;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const normalizedSenderId = normalizeText(senderId);
|
|
49
|
+
const normalizedAccountId = normalizeText(accountId);
|
|
50
|
+
const store = sessionStore && typeof sessionStore.getBinding === "function"
|
|
51
|
+
? sessionStore
|
|
52
|
+
: null;
|
|
53
|
+
|
|
54
|
+
if (store && normalizedSenderId && normalizedAccountId) {
|
|
55
|
+
const bindingKey = store.buildBindingKey({
|
|
56
|
+
workspaceId: config.workspaceId,
|
|
57
|
+
accountId: normalizedAccountId,
|
|
58
|
+
senderId: normalizedSenderId,
|
|
59
|
+
});
|
|
60
|
+
const activeWorkspaceRoot = normalizeText(store.getActiveWorkspaceRoot(bindingKey));
|
|
61
|
+
if (activeWorkspaceRoot) {
|
|
62
|
+
return activeWorkspaceRoot;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const binding = store.getBinding(bindingKey);
|
|
66
|
+
const boundWorkspaceRoots = collectWorkspaceRoots(binding);
|
|
67
|
+
if (boundWorkspaceRoots.length === 1) {
|
|
68
|
+
return boundWorkspaceRoots[0];
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const globalWorkspaceCandidates = collectBindingWorkspaceRoots({ config, accountId, sessionStore: store });
|
|
73
|
+
if (globalWorkspaceCandidates.length === 1) {
|
|
74
|
+
return globalWorkspaceCandidates[0];
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return normalizeText(config?.workspaceRoot);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function collectBindingSenderIds({ config, accountId, sessionStore }) {
|
|
81
|
+
const store = sessionStore && typeof sessionStore.getBinding === "function"
|
|
82
|
+
? sessionStore
|
|
83
|
+
: null;
|
|
84
|
+
if (!store) {
|
|
85
|
+
return [];
|
|
86
|
+
}
|
|
87
|
+
const normalizedAccountId = normalizeText(accountId);
|
|
88
|
+
if (!normalizedAccountId) {
|
|
89
|
+
return [];
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const senderIds = new Set();
|
|
93
|
+
for (const binding of Object.values(store.state?.bindings || {})) {
|
|
94
|
+
const bindingAccountId = normalizeText(binding?.accountId);
|
|
95
|
+
const bindingWorkspaceId = normalizeText(binding?.workspaceId);
|
|
96
|
+
const senderId = normalizeText(binding?.senderId);
|
|
97
|
+
if (!senderId || bindingAccountId !== normalizedAccountId) {
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
if (bindingWorkspaceId && bindingWorkspaceId !== normalizeText(config?.workspaceId)) {
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
senderIds.add(senderId);
|
|
104
|
+
}
|
|
105
|
+
return Array.from(senderIds).sort((left, right) => left.localeCompare(right));
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function collectBindingWorkspaceRoots({ config, accountId, sessionStore }) {
|
|
109
|
+
const store = sessionStore && typeof sessionStore.getBinding === "function"
|
|
110
|
+
? sessionStore
|
|
111
|
+
: null;
|
|
112
|
+
if (!store) {
|
|
113
|
+
return [];
|
|
114
|
+
}
|
|
115
|
+
const normalizedAccountId = normalizeText(accountId);
|
|
116
|
+
const workspaceRoots = new Set();
|
|
117
|
+
|
|
118
|
+
for (const binding of Object.values(store.state?.bindings || {})) {
|
|
119
|
+
const bindingAccountId = normalizeText(binding?.accountId);
|
|
120
|
+
const bindingWorkspaceId = normalizeText(binding?.workspaceId);
|
|
121
|
+
if (bindingAccountId !== normalizedAccountId) {
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
if (bindingWorkspaceId && bindingWorkspaceId !== normalizeText(config?.workspaceId)) {
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
for (const workspaceRoot of collectWorkspaceRoots(binding)) {
|
|
128
|
+
workspaceRoots.add(workspaceRoot);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return Array.from(workspaceRoots).sort((left, right) => left.localeCompare(right));
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function collectWorkspaceRoots(binding) {
|
|
136
|
+
const workspaceRoots = new Set();
|
|
137
|
+
const activeWorkspaceRoot = normalizeText(binding?.activeWorkspaceRoot);
|
|
138
|
+
if (activeWorkspaceRoot) {
|
|
139
|
+
workspaceRoots.add(activeWorkspaceRoot);
|
|
140
|
+
}
|
|
141
|
+
for (const workspaceRoot of Object.keys(binding?.threadIdByWorkspaceRoot || {})) {
|
|
142
|
+
const normalizedWorkspaceRoot = normalizeText(workspaceRoot);
|
|
143
|
+
if (normalizedWorkspaceRoot) {
|
|
144
|
+
workspaceRoots.add(normalizedWorkspaceRoot);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
for (const workspaceRoot of Object.keys(binding?.codexParamsByWorkspaceRoot || {})) {
|
|
148
|
+
const normalizedWorkspaceRoot = normalizeText(workspaceRoot);
|
|
149
|
+
if (normalizedWorkspaceRoot) {
|
|
150
|
+
workspaceRoots.add(normalizedWorkspaceRoot);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return Array.from(workspaceRoots).sort((left, right) => left.localeCompare(right));
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function normalizeText(value) {
|
|
157
|
+
return typeof value === "string" ? value.trim() : "";
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
module.exports = {
|
|
161
|
+
resolvePreferredSenderId,
|
|
162
|
+
resolvePreferredWorkspaceRoot,
|
|
163
|
+
};
|
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
const fs = require("fs");
|
|
2
|
+
const path = require("path");
|
|
3
|
+
|
|
4
|
+
const { listTrackedProjects } = require("./project-radar");
|
|
5
|
+
const { appendSection, findSectionRange, resolveNoteSyncTarget } = require("./note-sync");
|
|
6
|
+
|
|
7
|
+
function loadDurableNoteSchemaConfig(config = {}) {
|
|
8
|
+
const filePath = normalizeText(config.durableNoteSchemaConfigFile);
|
|
9
|
+
if (!filePath) {
|
|
10
|
+
return {};
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
let raw = "";
|
|
14
|
+
try {
|
|
15
|
+
raw = fs.readFileSync(filePath, "utf8");
|
|
16
|
+
} catch {
|
|
17
|
+
return {};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
const parsed = JSON.parse(raw);
|
|
22
|
+
return parsed && typeof parsed === "object" ? parsed : {};
|
|
23
|
+
} catch (error) {
|
|
24
|
+
throw new Error(`durable note schema 不是合法 JSON: ${filePath} (${formatErrorMessage(error)})`);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function resolveDurableNoteProfile(config = {}) {
|
|
29
|
+
const workspaceRoot = normalizeDisplayPath(path.resolve(String(config.workspaceRoot || process.cwd())));
|
|
30
|
+
const schemaConfig = loadDurableNoteSchemaConfig(config);
|
|
31
|
+
const workspaceProfile = selectWorkspaceProfile(schemaConfig.workspaces, workspaceRoot);
|
|
32
|
+
const projectDefaults = normalizeFamily(workspaceProfile?.projectDefaults);
|
|
33
|
+
const notes = normalizeNamedFamilies(workspaceProfile?.notes);
|
|
34
|
+
return {
|
|
35
|
+
workspaceRoot,
|
|
36
|
+
projectDefaults,
|
|
37
|
+
notes,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function inspectDurableNoteRouting(config = {}, options = {}) {
|
|
42
|
+
const profile = resolveDurableNoteProfile(config);
|
|
43
|
+
const project = normalizeText(options.project);
|
|
44
|
+
const scope = normalizeText(options.scope).toLowerCase();
|
|
45
|
+
const kind = normalizeText(options.kind).toLowerCase();
|
|
46
|
+
|
|
47
|
+
if (project) {
|
|
48
|
+
const target = resolveNoteSyncTarget(config, { project });
|
|
49
|
+
return buildInspectionResult({
|
|
50
|
+
mode: kind ? "route" : "family",
|
|
51
|
+
familyId: "project",
|
|
52
|
+
familyLabel: "tracked-project",
|
|
53
|
+
filePath: target.filePath,
|
|
54
|
+
sections: profile.projectDefaults.sections,
|
|
55
|
+
kinds: profile.projectDefaults.kinds,
|
|
56
|
+
kind,
|
|
57
|
+
extra: {
|
|
58
|
+
project: target.label,
|
|
59
|
+
availableProjects: listTrackedProjects(config).map((entry) => entry.slug),
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (scope) {
|
|
65
|
+
const family = profile.notes[scope];
|
|
66
|
+
if (!family) {
|
|
67
|
+
throw new Error(`找不到 durable note scope: ${scope};当前可用 scope: ${listAvailableScopes(profile).join(", ") || "none"}`);
|
|
68
|
+
}
|
|
69
|
+
return buildInspectionResult({
|
|
70
|
+
mode: kind ? "route" : "family",
|
|
71
|
+
familyId: scope,
|
|
72
|
+
familyLabel: family.label || scope,
|
|
73
|
+
filePath: resolveWorkspaceNotePath(profile.workspaceRoot, family.filePath),
|
|
74
|
+
sections: family.sections,
|
|
75
|
+
kinds: family.kinds,
|
|
76
|
+
kind,
|
|
77
|
+
extra: {},
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return {
|
|
82
|
+
mode: "overview",
|
|
83
|
+
workspaceRoot: profile.workspaceRoot,
|
|
84
|
+
project: {
|
|
85
|
+
availableProjects: listTrackedProjects(config).map((entry) => entry.slug),
|
|
86
|
+
sections: profile.projectDefaults.sections,
|
|
87
|
+
kinds: Object.keys(profile.projectDefaults.kinds),
|
|
88
|
+
},
|
|
89
|
+
scopes: Object.fromEntries(
|
|
90
|
+
Object.entries(profile.notes).map(([familyId, family]) => [
|
|
91
|
+
familyId,
|
|
92
|
+
{
|
|
93
|
+
label: family.label || familyId,
|
|
94
|
+
filePath: resolveWorkspaceNotePath(profile.workspaceRoot, family.filePath),
|
|
95
|
+
sections: [...family.sections],
|
|
96
|
+
kinds: Object.keys(family.kinds),
|
|
97
|
+
},
|
|
98
|
+
])
|
|
99
|
+
),
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function resolveDurableNoteRoute(config = {}, options = {}) {
|
|
104
|
+
const inspection = inspectDurableNoteRouting(config, options);
|
|
105
|
+
if (inspection.mode !== "route") {
|
|
106
|
+
throw new Error("缺少完整 durable note 路由参数:至少传 --kind,并配合 --project 或 --scope");
|
|
107
|
+
}
|
|
108
|
+
return inspection.route;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function ensureDurableNoteSections(filePath, sections = []) {
|
|
112
|
+
const normalizedPath = normalizeText(filePath);
|
|
113
|
+
if (!normalizedPath) {
|
|
114
|
+
throw new Error("durable note filePath 不能为空");
|
|
115
|
+
}
|
|
116
|
+
if (!fs.existsSync(normalizedPath)) {
|
|
117
|
+
throw new Error(`durable note 文件不存在: ${normalizedPath}`);
|
|
118
|
+
}
|
|
119
|
+
const stat = fs.statSync(normalizedPath);
|
|
120
|
+
if (!stat.isFile()) {
|
|
121
|
+
throw new Error(`durable note 目标不是文件: ${normalizedPath}`);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
let content = normalizeLineEnding(fs.readFileSync(normalizedPath, "utf8"));
|
|
125
|
+
let changed = false;
|
|
126
|
+
const createdSections = [];
|
|
127
|
+
for (const section of Array.isArray(sections) ? sections : []) {
|
|
128
|
+
const normalizedSection = normalizeText(section);
|
|
129
|
+
if (!normalizedSection) {
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
if (findSectionRange(content, normalizedSection)) {
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
content = appendSection(content, normalizedSection);
|
|
136
|
+
createdSections.push(normalizedSection);
|
|
137
|
+
changed = true;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (changed) {
|
|
141
|
+
fs.writeFileSync(normalizedPath, ensureTrailingNewline(content), "utf8");
|
|
142
|
+
}
|
|
143
|
+
return {
|
|
144
|
+
changed,
|
|
145
|
+
createdSections,
|
|
146
|
+
filePath: normalizeDisplayPath(normalizedPath),
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function buildInspectionResult({ mode, familyId, familyLabel, filePath, sections, kinds, kind, extra }) {
|
|
151
|
+
const availableKinds = Object.keys(kinds);
|
|
152
|
+
if (!kind) {
|
|
153
|
+
return {
|
|
154
|
+
mode,
|
|
155
|
+
family: familyId,
|
|
156
|
+
label: familyLabel,
|
|
157
|
+
filePath,
|
|
158
|
+
sections: [...sections],
|
|
159
|
+
kinds: availableKinds,
|
|
160
|
+
...extra,
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const matchedKind = kinds[kind];
|
|
165
|
+
if (!matchedKind) {
|
|
166
|
+
throw new Error(`scope ${familyId} 不支持 kind: ${kind};当前可用 kinds: ${availableKinds.join(", ") || "none"}`);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return {
|
|
170
|
+
mode,
|
|
171
|
+
family: familyId,
|
|
172
|
+
label: familyLabel,
|
|
173
|
+
filePath,
|
|
174
|
+
sections: [...sections],
|
|
175
|
+
kinds: availableKinds,
|
|
176
|
+
route: {
|
|
177
|
+
family: familyId,
|
|
178
|
+
kind,
|
|
179
|
+
filePath,
|
|
180
|
+
section: matchedKind.section,
|
|
181
|
+
style: matchedKind.style,
|
|
182
|
+
slot: matchedKind.slot,
|
|
183
|
+
maxItems: matchedKind.maxItems,
|
|
184
|
+
sections: [...sections],
|
|
185
|
+
},
|
|
186
|
+
...extra,
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function selectWorkspaceProfile(workspaces, workspaceRoot) {
|
|
191
|
+
if (!workspaces || typeof workspaces !== "object") {
|
|
192
|
+
return {};
|
|
193
|
+
}
|
|
194
|
+
const normalizedWorkspaceRoot = normalizeDisplayPath(workspaceRoot);
|
|
195
|
+
for (const [candidateRoot, profile] of Object.entries(workspaces)) {
|
|
196
|
+
if (normalizeDisplayPath(candidateRoot) === normalizedWorkspaceRoot) {
|
|
197
|
+
return profile && typeof profile === "object" ? profile : {};
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
return {};
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function normalizeNamedFamilies(rawFamilies) {
|
|
204
|
+
if (!rawFamilies || typeof rawFamilies !== "object") {
|
|
205
|
+
return {};
|
|
206
|
+
}
|
|
207
|
+
const entries = Object.entries(rawFamilies)
|
|
208
|
+
.map(([familyId, rawFamily]) => {
|
|
209
|
+
const normalizedId = normalizeText(familyId).toLowerCase();
|
|
210
|
+
const family = normalizeFamily(rawFamily);
|
|
211
|
+
if (!normalizedId || !family.filePath || !Object.keys(family.kinds).length) {
|
|
212
|
+
return null;
|
|
213
|
+
}
|
|
214
|
+
return [normalizedId, { ...family, label: normalizeText(rawFamily?.label) || normalizedId }];
|
|
215
|
+
})
|
|
216
|
+
.filter(Boolean);
|
|
217
|
+
return Object.fromEntries(entries);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function normalizeFamily(rawFamily) {
|
|
221
|
+
const family = rawFamily && typeof rawFamily === "object" ? rawFamily : {};
|
|
222
|
+
return {
|
|
223
|
+
filePath: normalizeRelativeOrAbsolutePath(family.path),
|
|
224
|
+
sections: normalizeSections(family.sections),
|
|
225
|
+
kinds: normalizeKinds(family.kinds),
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function normalizeKinds(rawKinds) {
|
|
230
|
+
if (!rawKinds || typeof rawKinds !== "object") {
|
|
231
|
+
return {};
|
|
232
|
+
}
|
|
233
|
+
const entries = Object.entries(rawKinds)
|
|
234
|
+
.map(([kind, rawRoute]) => {
|
|
235
|
+
const normalizedKind = normalizeText(kind).toLowerCase();
|
|
236
|
+
const route = normalizeRoute(rawRoute);
|
|
237
|
+
if (!normalizedKind || !route) {
|
|
238
|
+
return null;
|
|
239
|
+
}
|
|
240
|
+
return [normalizedKind, route];
|
|
241
|
+
})
|
|
242
|
+
.filter(Boolean);
|
|
243
|
+
return Object.fromEntries(entries);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
function normalizeRoute(rawRoute) {
|
|
247
|
+
const route = rawRoute && typeof rawRoute === "object" ? rawRoute : {};
|
|
248
|
+
const section = normalizeText(route.section);
|
|
249
|
+
if (!section) {
|
|
250
|
+
return null;
|
|
251
|
+
}
|
|
252
|
+
return {
|
|
253
|
+
section,
|
|
254
|
+
style: normalizeText(route.style).toLowerCase() === "paragraph" ? "paragraph" : "bullet",
|
|
255
|
+
slot: normalizeText(route.slot),
|
|
256
|
+
maxItems: normalizePositiveInteger(route.maxItems),
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
function normalizeSections(rawSections) {
|
|
261
|
+
return Array.isArray(rawSections)
|
|
262
|
+
? rawSections.map((section) => normalizeText(section)).filter(Boolean)
|
|
263
|
+
: [];
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
function normalizePositiveInteger(value) {
|
|
267
|
+
const raw = String(value || "").trim();
|
|
268
|
+
if (!raw) {
|
|
269
|
+
return 0;
|
|
270
|
+
}
|
|
271
|
+
const parsed = Number.parseInt(raw, 10);
|
|
272
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : 0;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
function normalizeRelativeOrAbsolutePath(targetPath) {
|
|
276
|
+
const normalized = normalizeText(targetPath);
|
|
277
|
+
if (!normalized) {
|
|
278
|
+
return "";
|
|
279
|
+
}
|
|
280
|
+
return normalized.replace(/\\/g, "/");
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
function resolveWorkspaceNotePath(workspaceRoot, targetPath) {
|
|
284
|
+
const normalizedTargetPath = normalizeText(targetPath);
|
|
285
|
+
if (!normalizedTargetPath) {
|
|
286
|
+
return "";
|
|
287
|
+
}
|
|
288
|
+
if (path.isAbsolute(normalizedTargetPath)) {
|
|
289
|
+
return normalizeDisplayPath(path.resolve(normalizedTargetPath));
|
|
290
|
+
}
|
|
291
|
+
return normalizeDisplayPath(path.resolve(workspaceRoot, ...normalizedTargetPath.split("/")));
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
function listAvailableScopes(profile) {
|
|
295
|
+
return Object.keys(profile.notes || {});
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
function normalizeText(value) {
|
|
299
|
+
return typeof value === "string" ? value.trim() : "";
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
function normalizeDisplayPath(targetPath) {
|
|
303
|
+
return normalizeText(targetPath).replace(/\\/g, "/");
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
function normalizeLineEnding(value) {
|
|
307
|
+
return String(value || "").replace(/\r\n/g, "\n");
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
function ensureTrailingNewline(value) {
|
|
311
|
+
const normalized = normalizeLineEnding(value);
|
|
312
|
+
return normalized.endsWith("\n") ? normalized : `${normalized}\n`;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
function formatErrorMessage(error) {
|
|
316
|
+
return error instanceof Error ? error.message : String(error || "unknown error");
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
module.exports = {
|
|
320
|
+
ensureDurableNoteSections,
|
|
321
|
+
inspectDurableNoteRouting,
|
|
322
|
+
loadDurableNoteSchemaConfig,
|
|
323
|
+
resolveDurableNoteProfile,
|
|
324
|
+
resolveDurableNoteRoute,
|
|
325
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
function resolveUserPronoun(gender) {
|
|
2
|
+
const normalized = String(gender || "").trim().toLowerCase();
|
|
3
|
+
if (normalized === "male" || normalized === "man" || normalized === "m" || normalized === "男") {
|
|
4
|
+
return "他";
|
|
5
|
+
}
|
|
6
|
+
if (normalized === "neutral" || normalized === "nonbinary" || normalized === "nb" || normalized === "ta") {
|
|
7
|
+
return "TA";
|
|
8
|
+
}
|
|
9
|
+
return "她";
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function renderInstructionTemplate(template, config = {}) {
|
|
13
|
+
const userName = String(config?.userName || "").trim() || "用户";
|
|
14
|
+
const pronoun = resolveUserPronoun(config?.userGender);
|
|
15
|
+
const codekseiHome = String(
|
|
16
|
+
config?.codekseiHome
|
|
17
|
+
|| config?.cyberbossHome
|
|
18
|
+
|| process.env.CODEKSEI_HOME
|
|
19
|
+
|| process.env.CYBERBOSS_HOME
|
|
20
|
+
|| ""
|
|
21
|
+
).trim();
|
|
22
|
+
return String(template || "")
|
|
23
|
+
.replaceAll("{{USER_NAME}}", userName)
|
|
24
|
+
.replaceAll("{{CYBERBOSS_HOME}}", codekseiHome)
|
|
25
|
+
.replaceAll("她", pronoun);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
module.exports = {
|
|
29
|
+
renderInstructionTemplate,
|
|
30
|
+
resolveUserPronoun,
|
|
31
|
+
};
|