nolo-cli 0.1.41 → 0.1.42
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 +27 -12
- package/agent-runtime/agentThread.ts +222 -0
- package/agent-runtime/agentThreadAdmission.ts +74 -0
- package/agent-runtime/dialogWritePlan.ts +42 -0
- package/agent-runtime/hostAdapter.ts +1 -0
- package/agent-runtime/index.ts +43 -0
- package/agent-runtime/localLoop.ts +31 -2
- package/agent-runtime/localToolPolicy.ts +1 -0
- package/agent-runtime/localWorkspaceTools.ts +1258 -78
- package/agent-runtime/noloWorkspaceTools.ts +20 -1
- package/agent-runtime/runtimeToolPolicy.ts +1 -5
- package/agent-runtime/runtimeToolSurface.ts +1 -0
- package/agentAliases.ts +29 -9
- package/agentInternalCommandEntries.ts +11 -3
- package/agentMachineCommands.ts +1 -0
- package/agentRecordCommands.ts +2 -2
- package/agentRecordHelpers.ts +59 -6
- package/agentRunCommand.ts +84 -19
- package/ai/agent/buildSystemPrompt.ts +14 -0
- package/ai/agent/cliExecutor.ts +202 -43
- package/ai/agent/createAgentSchema.ts +2 -2
- package/ai/agent/liveAudioModel.ts +1 -1
- package/ai/agent/streamAgentChatTurn.ts +154 -20
- package/ai/agent/streamAgentChatTurnUtils.ts +63 -0
- package/ai/ai.locale.ts +70 -0
- package/ai/chat/inlineImageUrlsForCustomProvider.ts +7 -2
- package/ai/chat/sendOpenAICompletionsRequest.ts +25 -1
- package/ai/llm/kimi.ts +0 -1
- package/ai/llm/openrouterModels.ts +27 -2
- package/ai/memory/policy.ts +49 -0
- package/ai/memory/queryShared.ts +10 -4
- package/ai/memory/recentRelationshipRecap.ts +4 -0
- package/ai/memory/remember.ts +48 -104
- package/ai/memory/scope.ts +74 -0
- package/ai/memory/types.ts +6 -0
- package/ai/memory/understanding.ts +10 -18
- package/ai/policy/runtimePolicy.ts +95 -23
- package/ai/tools/agent/agentTools.ts +0 -21
- package/ai/tools/agent/startAgentDialogTool.ts +2 -1
- package/ai/tools/index.ts +2 -20
- package/ai/tools/prepareTools.ts +171 -1
- package/ai/tools/readXhsProfileTool.ts +80 -69
- package/ai/tools/table/createTableTool.ts +11 -0
- package/ai/tools/toolPacks.ts +19 -0
- package/ai/types.ts +3 -0
- package/app/favorite/deletedFavoriteProjection.ts +31 -0
- package/app/hooks/deleteDbKey.ts +24 -3
- package/app/i18n/translations/interface.locale.ts +48 -16
- package/app/types/appSummary.ts +4 -0
- package/app/utils/desktopAgentRuntimeTurnClient.ts +2 -0
- package/auth/adminPermissions.ts +64 -4
- package/auth/routes.ts +5 -0
- package/chat/chat.locale.ts +4 -0
- package/chat/dialog/actions/handleSendMessageAction.ts +7 -2
- package/chat/dialog/dialogAttachmentCleanup.ts +135 -0
- package/chat/dialog/dialogSlice.ts +117 -4
- package/chat/messages/activityCompletion.ts +97 -0
- package/chat/messages/imagePayloadPersistence.ts +22 -0
- package/chat/messages/messageContent.ts +20 -16
- package/chat/messages/messageSlice.ts +20 -1
- package/chat/messages/toolThunks.ts +32 -11
- package/chat/messages/types.ts +8 -1
- package/chat/messages/web/toolDisplayName.ts +686 -0
- package/cli/agentAliases.ts +29 -9
- package/cli/agentInternalCommandEntries.ts +11 -3
- package/cli/agentMachineCommands.ts +1 -0
- package/cli/agentRecordCommands.ts +2 -2
- package/cli/agentRecordHelpers.ts +59 -6
- package/cli/agentRunCommand.ts +84 -19
- package/cli/client/agentRun.ts +65 -253
- package/cli/client/localRuntimeAdapter.ts +179 -53
- package/cli/commandRegistry.ts +7 -4
- package/cli/dialogAttachmentCleanup.ts +151 -0
- package/cli/dialogCommands.ts +163 -61
- package/cli/dialogInternalCommandEntries.ts +1 -1
- package/cli/docCreateCommands.ts +345 -0
- package/cli/docInternalCommandEntries.ts +11 -0
- package/cli/docPageHelpers.ts +80 -0
- package/cli/docSkillHelpers.ts +67 -0
- package/cli/docSpaceHelpers.ts +46 -0
- package/cli/internalCommandEntries.ts +4 -0
- package/cli/machineCommands.ts +18 -34
- package/cli/memoryCommands.ts +253 -0
- package/cli/memoryInternalCommandEntries.ts +9 -0
- package/cli/qoderUsageProbe.ts +252 -0
- package/cli/scriptCommandEntries.ts +0 -3
- package/cli/secretScan.ts +31 -0
- package/cli/tableCommands.ts +248 -13
- package/cli/workflowInternalCommandEntries.ts +2 -3
- package/client/agentRun.test.ts +68 -84
- package/client/agentRun.ts +65 -253
- package/client/localRuntimeAdapter.test.ts +505 -74
- package/client/localRuntimeAdapter.ts +179 -53
- package/commandRegistry.ts +7 -4
- package/connector-experimental/capabilities.ts +10 -9
- package/create/space/sidebarVisibleTypes.ts +19 -0
- package/dialogAttachmentCleanup.ts +151 -0
- package/dialogCommands.ts +163 -61
- package/dialogInternalCommandEntries.ts +1 -1
- package/docCreateCommands.ts +345 -0
- package/docInternalCommandEntries.ts +11 -0
- package/docPageHelpers.ts +80 -0
- package/docSkillHelpers.ts +67 -0
- package/docSpaceHelpers.ts +46 -0
- package/integrations/google/models.ts +4 -4
- package/integrations/openai/generateOpenAIRequestBody.ts +0 -3
- package/integrations/xhs-reader/types.ts +36 -3
- package/integrations/xhs-reader/url.ts +24 -1
- package/internalCommandEntries.ts +4 -0
- package/machineCommands.ts +18 -34
- package/memoryCommands.ts +253 -0
- package/memoryInternalCommandEntries.ts +9 -0
- package/package.json +133 -114
- package/qoderUsageProbe.ts +252 -0
- package/render/contentIcon/types.ts +167 -0
- package/render/page/docSlice.ts +30 -3
- package/render/page/types.ts +2 -0
- package/render/table/createTableAction.ts +4 -0
- package/render/table/tableSlice.ts +61 -0
- package/render/table/types.ts +10 -0
- package/scriptCommandEntries.ts +0 -3
- package/secretScan.ts +31 -0
- package/server/handlers/agentRun/types.ts +24 -23
- package/tableCommands.ts +248 -13
- package/workflowInternalCommandEntries.ts +2 -3
- package/ai/tools/agent/taskRunTool.ts +0 -112
- package/cli/client/taskRunPrompt.ts +0 -27
- package/cli/taskRunCommand.ts +0 -265
- package/client/taskRunPrompt.ts +0 -27
- package/integrations/xhs-reader/analyze/profileAnalyzer.ts +0 -205
- package/integrations/xhs-reader/backends/playwrightProfileCollector.ts +0 -624
- package/integrations/xhs-reader/bridge/readXhsProfileWithBridge.ts +0 -227
- package/integrations/xhs-reader/client/xhsWebApiClient.ts +0 -229
- package/integrations/xhs-reader/normalize.ts +0 -390
- package/integrations/xhs-reader/orchestrator.ts +0 -178
- package/taskRunCommand.ts +0 -265
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { ulid } from "ulid";
|
|
3
|
+
|
|
4
|
+
function getCliArg(args: string[], flag: string): string | undefined {
|
|
5
|
+
const idx = args.indexOf(flag);
|
|
6
|
+
return idx !== -1 ? args[idx + 1] : undefined;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function readBodyArg(args: string[], fallback = "") {
|
|
10
|
+
const bodyFile = getCliArg(args, "--body-file");
|
|
11
|
+
if (bodyFile !== undefined) {
|
|
12
|
+
return readFileSync(bodyFile, "utf8");
|
|
13
|
+
}
|
|
14
|
+
return getCliArg(args, "--body") ?? fallback;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function textToSlate(text: string) {
|
|
18
|
+
return text.split("\n").map((line) => ({
|
|
19
|
+
type: "paragraph",
|
|
20
|
+
children: [{ text: line }],
|
|
21
|
+
}));
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function createPageId() {
|
|
25
|
+
return ulid();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function buildPageKey(userId: string, pageId: string) {
|
|
29
|
+
return `page-${userId}-${pageId}`;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function buildPageRecord(args: {
|
|
33
|
+
dbKey: string;
|
|
34
|
+
pageId: string;
|
|
35
|
+
title: string;
|
|
36
|
+
spaceId: string | null;
|
|
37
|
+
content: string;
|
|
38
|
+
existing?: Record<string, any> | null;
|
|
39
|
+
meta?: Record<string, any> | null;
|
|
40
|
+
slateData?: Record<string, any>[] | null;
|
|
41
|
+
}) {
|
|
42
|
+
const { dbKey, pageId, title, spaceId, content, existing, meta, slateData } = args;
|
|
43
|
+
const now = Date.now();
|
|
44
|
+
const createdAt = typeof existing?.createdAt === "number" ? existing.createdAt : now;
|
|
45
|
+
const created =
|
|
46
|
+
typeof existing?.created === "string" ? existing.created : new Date(createdAt).toISOString();
|
|
47
|
+
|
|
48
|
+
const nextRecord: Record<string, any> = {
|
|
49
|
+
...(existing ?? {}),
|
|
50
|
+
id: existing?.id ?? pageId,
|
|
51
|
+
dbKey,
|
|
52
|
+
type: "page",
|
|
53
|
+
title,
|
|
54
|
+
spaceId,
|
|
55
|
+
content,
|
|
56
|
+
updatedAt: now,
|
|
57
|
+
createdAt,
|
|
58
|
+
created,
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
if (meta !== undefined) {
|
|
62
|
+
if (meta === null) {
|
|
63
|
+
delete nextRecord.meta;
|
|
64
|
+
} else {
|
|
65
|
+
nextRecord.meta = meta;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (slateData !== undefined) {
|
|
70
|
+
if (slateData === null) {
|
|
71
|
+
delete nextRecord.slateData;
|
|
72
|
+
} else {
|
|
73
|
+
nextRecord.slateData = slateData;
|
|
74
|
+
}
|
|
75
|
+
} else if (!existing?.slateData) {
|
|
76
|
+
nextRecord.slateData = textToSlate(content);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return nextRecord;
|
|
80
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import {
|
|
2
|
+
buildSkillDocMarkdown,
|
|
3
|
+
type SkillDocConfig,
|
|
4
|
+
} from "./ai/skills/skillDocProtocol";
|
|
5
|
+
import { buildPageKey, buildPageRecord } from "./docPageHelpers";
|
|
6
|
+
|
|
7
|
+
function normalizeSkillSeed(input: string) {
|
|
8
|
+
return input
|
|
9
|
+
.trim()
|
|
10
|
+
.toLowerCase()
|
|
11
|
+
.replace(/[^a-z0-9\u4e00-\u9fa5]+/g, "-")
|
|
12
|
+
.replace(/^-+|-+$/g, "");
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function deterministicId(prefix: string, seed: string): string {
|
|
16
|
+
let h = 0x811c9dc5;
|
|
17
|
+
for (let i = 0; i < seed.length; i++) {
|
|
18
|
+
h ^= seed.charCodeAt(i);
|
|
19
|
+
h = (h * 0x01000193) >>> 0;
|
|
20
|
+
}
|
|
21
|
+
const suffix = h.toString(36).toUpperCase().padStart(14, "0");
|
|
22
|
+
return (prefix + suffix).slice(0, 26);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function buildSkillDocId(input: string) {
|
|
26
|
+
return deterministicId("01SK", normalizeSkillSeed(input) || input);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function buildSkillPageKey(userId: string, skillId: string) {
|
|
30
|
+
return buildPageKey(userId, skillId);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function buildSkillPageRecord(args: {
|
|
34
|
+
dbKey: string;
|
|
35
|
+
skillId: string;
|
|
36
|
+
title: string;
|
|
37
|
+
spaceId: string | null;
|
|
38
|
+
body: string;
|
|
39
|
+
skillConfig: SkillDocConfig;
|
|
40
|
+
existing?: Record<string, any> | null;
|
|
41
|
+
}) {
|
|
42
|
+
const { dbKey, skillId, title, spaceId, body, skillConfig, existing } = args;
|
|
43
|
+
return {
|
|
44
|
+
...buildPageRecord({
|
|
45
|
+
dbKey,
|
|
46
|
+
pageId: skillId,
|
|
47
|
+
title,
|
|
48
|
+
spaceId,
|
|
49
|
+
content: buildSkillDocMarkdown({
|
|
50
|
+
body,
|
|
51
|
+
skillConfig,
|
|
52
|
+
}),
|
|
53
|
+
existing,
|
|
54
|
+
meta: {
|
|
55
|
+
...(existing?.meta ?? {}),
|
|
56
|
+
kind: "skill",
|
|
57
|
+
skillConfig,
|
|
58
|
+
},
|
|
59
|
+
slateData: null,
|
|
60
|
+
}),
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function parseJsonArg<T>(raw: string | undefined, fallback: T): T {
|
|
65
|
+
if (raw === undefined) return fallback;
|
|
66
|
+
return JSON.parse(raw) as T;
|
|
67
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { createSpaceKey } from "./create/space/spaceKeys";
|
|
2
|
+
import { readDbRecord, writeAgentRecord } from "./agentRecordHelpers";
|
|
3
|
+
|
|
4
|
+
export async function ensurePageAttachedToSpace(params: {
|
|
5
|
+
baseUrl: string;
|
|
6
|
+
userId: string;
|
|
7
|
+
authToken: string;
|
|
8
|
+
spaceId: string;
|
|
9
|
+
contentKey: string;
|
|
10
|
+
title: string;
|
|
11
|
+
skillSummary?: Record<string, any> | null;
|
|
12
|
+
}) {
|
|
13
|
+
const { baseUrl, userId, authToken, spaceId, contentKey, title, skillSummary } = params;
|
|
14
|
+
const spaceKey = createSpaceKey.space(spaceId);
|
|
15
|
+
const spaceRecord = await readDbRecord({
|
|
16
|
+
dbKey: spaceKey,
|
|
17
|
+
authToken,
|
|
18
|
+
fetchImpl: fetch,
|
|
19
|
+
serverUrl: baseUrl,
|
|
20
|
+
});
|
|
21
|
+
const now = Date.now();
|
|
22
|
+
|
|
23
|
+
await writeAgentRecord({
|
|
24
|
+
agentKey: spaceKey,
|
|
25
|
+
authToken,
|
|
26
|
+
fetchImpl: fetch,
|
|
27
|
+
serverUrl: baseUrl,
|
|
28
|
+
userId,
|
|
29
|
+
record: {
|
|
30
|
+
...spaceRecord,
|
|
31
|
+
contents: {
|
|
32
|
+
...(spaceRecord.contents ?? {}),
|
|
33
|
+
[contentKey]: {
|
|
34
|
+
...(spaceRecord.contents?.[contentKey] ?? {}),
|
|
35
|
+
title,
|
|
36
|
+
type: "page",
|
|
37
|
+
contentKey,
|
|
38
|
+
...(skillSummary !== undefined ? { skillSummary } : {}),
|
|
39
|
+
updatedAt: now,
|
|
40
|
+
createdAt: spaceRecord.contents?.[contentKey]?.createdAt ?? now,
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
updatedAt: now,
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
}
|
|
@@ -67,14 +67,14 @@ const createGoogleImageModel = ({
|
|
|
67
67
|
export const googleModels: Model[] = [
|
|
68
68
|
{
|
|
69
69
|
name: DEFAULT_GOOGLE_LIVE_AUDIO_MODEL,
|
|
70
|
-
displayName: "Gemini
|
|
70
|
+
displayName: "Gemini 3.1 Flash Live",
|
|
71
71
|
provider: "google",
|
|
72
72
|
description:
|
|
73
|
-
"
|
|
73
|
+
"Gemini Live API model for low-latency real-time voice conversations.",
|
|
74
74
|
hasVision: true,
|
|
75
75
|
hasAudio: true,
|
|
76
|
-
contextWindow:
|
|
77
|
-
maxOutputTokens:
|
|
76
|
+
contextWindow: 1048576,
|
|
77
|
+
maxOutputTokens: 65500,
|
|
78
78
|
supportsTool: true,
|
|
79
79
|
price: {
|
|
80
80
|
input: 0.5 * 7,
|
|
@@ -102,9 +102,6 @@ const shouldDisableKimiThinking = (
|
|
|
102
102
|
if (agentConfig.enableThinking !== false) return false;
|
|
103
103
|
if (providerName === "deepinfra") return isDeepInfraKimiModel(resolvedModel);
|
|
104
104
|
if (providerName === "fireworks") return isFireworksKimiModel(resolvedModel);
|
|
105
|
-
if (providerName === "openrouter") {
|
|
106
|
-
return resolvedModel.toLowerCase() === "moonshotai/kimi-k2.6";
|
|
107
|
-
}
|
|
108
105
|
return false;
|
|
109
106
|
};
|
|
110
107
|
|
|
@@ -17,6 +17,7 @@ export type XhsReadFailure = {
|
|
|
17
17
|
ok: false;
|
|
18
18
|
code: XhsFailureCode;
|
|
19
19
|
message: string;
|
|
20
|
+
diagnostic?: XhsCollectorDiagnostic;
|
|
20
21
|
fetchedAt: string;
|
|
21
22
|
};
|
|
22
23
|
|
|
@@ -41,6 +42,8 @@ export type XhsCollectorDiagnostic = {
|
|
|
41
42
|
finalUrl?: string;
|
|
42
43
|
/** Whether a login wall / prompt was detected on the page. */
|
|
43
44
|
loginDetected?: boolean;
|
|
45
|
+
/** Whether a visible login prompt close button was clicked before declaring the page blocked. */
|
|
46
|
+
loginPromptDismissed?: boolean;
|
|
44
47
|
/** Whether a captcha / verification wall was detected. */
|
|
45
48
|
captchaDetected?: boolean;
|
|
46
49
|
/** Whether __INITIAL_STATE__ was present and non-empty. */
|
|
@@ -53,6 +56,12 @@ export type XhsCollectorDiagnostic = {
|
|
|
53
56
|
firstApiResponseStatus?: number;
|
|
54
57
|
/** Whether the page URL after navigation looks like a redirect to login. */
|
|
55
58
|
redirectedToLogin?: boolean;
|
|
59
|
+
/** Length of visible body text sampled for diagnostics. */
|
|
60
|
+
bodyTextLength?: number;
|
|
61
|
+
/** Number of visible login close/dismiss candidates found on the page. */
|
|
62
|
+
visibleCloseCandidateCount?: number;
|
|
63
|
+
/** Number of visible XHS note links found on the page. */
|
|
64
|
+
visibleNoteLinkCount?: number;
|
|
56
65
|
};
|
|
57
66
|
|
|
58
67
|
// --- Profile ---
|
|
@@ -80,6 +89,7 @@ export type XhsNoteSummary = {
|
|
|
80
89
|
likedCount?: number;
|
|
81
90
|
// kept from initial state / user_posted page
|
|
82
91
|
xsecToken?: string; // internal use only - must not appear in public exports
|
|
92
|
+
xsecSource?: string; // internal navigation hint only - must not appear in public exports
|
|
83
93
|
};
|
|
84
94
|
|
|
85
95
|
// --- Note Detail ---
|
|
@@ -154,10 +164,19 @@ export type XhsProfileAnalysis = {
|
|
|
154
164
|
// --- Collection Status (assisted mode) ---
|
|
155
165
|
|
|
156
166
|
export type XhsCollectionMode = "conservative" | "assisted";
|
|
157
|
-
export type XhsAssistedAction =
|
|
167
|
+
export type XhsAssistedAction =
|
|
168
|
+
| "snapshot"
|
|
169
|
+
| "read_more_notes"
|
|
170
|
+
| "read_visible_details"
|
|
171
|
+
| "discover_indexed_notes";
|
|
158
172
|
|
|
159
173
|
export type XhsNextSuggestedAction = {
|
|
160
|
-
action:
|
|
174
|
+
action:
|
|
175
|
+
| "read_more_notes"
|
|
176
|
+
| "read_visible_details"
|
|
177
|
+
| "discover_indexed_notes"
|
|
178
|
+
| "save_to_table"
|
|
179
|
+
| "stop_anonymous_unavailable";
|
|
161
180
|
label: string;
|
|
162
181
|
reason: string;
|
|
163
182
|
};
|
|
@@ -184,6 +203,12 @@ export type XhsProfileCollection = {
|
|
|
184
203
|
noteDetails: XhsNoteDetail[];
|
|
185
204
|
commentsByNote: Record<string, XhsComment[]>;
|
|
186
205
|
analysis: XhsProfileAnalysis;
|
|
206
|
+
indexedDiscovery?: {
|
|
207
|
+
source: "external_index";
|
|
208
|
+
requestedNoteUrls: string[];
|
|
209
|
+
acceptedNoteUrls: string[];
|
|
210
|
+
verifiedNoteUrls: string[];
|
|
211
|
+
};
|
|
187
212
|
/** Present only when the collector detected an issue. Never contains secrets. */
|
|
188
213
|
diagnostic?: XhsCollectorDiagnostic;
|
|
189
214
|
/** Collection status for assisted automation mode. */
|
|
@@ -195,12 +220,16 @@ export type XhsProfileCollection = {
|
|
|
195
220
|
export type XhsParsedProfileUrl = {
|
|
196
221
|
userId: string;
|
|
197
222
|
canonicalUrl: string;
|
|
223
|
+
navigationUrl: string;
|
|
224
|
+
xsecToken?: string; // preserved internally only
|
|
225
|
+
xsecSource?: string; // preserved internally only
|
|
198
226
|
};
|
|
199
227
|
|
|
200
228
|
export type XhsParsedNoteUrl = {
|
|
201
229
|
noteId: string;
|
|
202
230
|
canonicalUrl: string;
|
|
203
231
|
xsecToken?: string; // preserved internally only
|
|
232
|
+
xsecSource?: string; // preserved internally only
|
|
204
233
|
};
|
|
205
234
|
|
|
206
235
|
// --- Redaction ---
|
|
@@ -211,7 +240,7 @@ export type XhsConnectorOptions = {
|
|
|
211
240
|
enrichDetails?: boolean; // default false
|
|
212
241
|
includeComments?: boolean; // default false
|
|
213
242
|
maxCommentPagesPerNote?: number; // default 1
|
|
214
|
-
headless?: boolean; // default
|
|
243
|
+
headless?: boolean; // default false
|
|
215
244
|
cookieDir?: string;
|
|
216
245
|
fetchImpl?: typeof fetch;
|
|
217
246
|
/** Assisted mode: "conservative" (default) or "assisted" */
|
|
@@ -220,17 +249,21 @@ export type XhsConnectorOptions = {
|
|
|
220
249
|
assistedAction?: XhsAssistedAction;
|
|
221
250
|
/** Max assisted steps (1..3), bounds scroll/comment pages */
|
|
222
251
|
maxAssistedSteps?: number;
|
|
252
|
+
/** Public note URLs discovered from an external search index. */
|
|
253
|
+
indexedNoteUrls?: string[];
|
|
223
254
|
};
|
|
224
255
|
|
|
225
256
|
// Helper to create failure
|
|
226
257
|
export function createXhsFailure(args: {
|
|
227
258
|
code: XhsFailureCode;
|
|
228
259
|
message: string;
|
|
260
|
+
diagnostic?: XhsCollectorDiagnostic;
|
|
229
261
|
}): XhsReadFailure {
|
|
230
262
|
return {
|
|
231
263
|
ok: false,
|
|
232
264
|
code: args.code,
|
|
233
265
|
message: args.message,
|
|
266
|
+
...(args.diagnostic ? { diagnostic: args.diagnostic } : {}),
|
|
234
267
|
fetchedAt: new Date().toISOString(),
|
|
235
268
|
};
|
|
236
269
|
}
|
|
@@ -9,6 +9,7 @@ const NOTE_RE =
|
|
|
9
9
|
/**
|
|
10
10
|
* Parse a XHS profile URL and return userId + canonical URL.
|
|
11
11
|
* Accepts full URLs and path-only forms.
|
|
12
|
+
* The xsecToken query param is preserved in the result for internal navigation only.
|
|
12
13
|
*/
|
|
13
14
|
export function parseXhsProfileUrl(input: string): XhsParsedProfileUrl {
|
|
14
15
|
const match = input.match(PROFILE_RE);
|
|
@@ -16,9 +17,28 @@ export function parseXhsProfileUrl(input: string): XhsParsedProfileUrl {
|
|
|
16
17
|
throw new Error(`Invalid XHS profile URL: ${input}`);
|
|
17
18
|
}
|
|
18
19
|
const userId = match[1];
|
|
20
|
+
const canonicalUrl = `https://www.xiaohongshu.com/user/profile/${userId}`;
|
|
21
|
+
|
|
22
|
+
let xsecToken: string | undefined;
|
|
23
|
+
let xsecSource: string | undefined;
|
|
24
|
+
try {
|
|
25
|
+
const urlObj = new URL(input.startsWith("http") ? input : `https://www.xiaohongshu.com${input}`);
|
|
26
|
+
xsecToken = urlObj.searchParams.get("xsec_token") ?? undefined;
|
|
27
|
+
xsecSource = urlObj.searchParams.get("xsec_source") ?? undefined;
|
|
28
|
+
} catch {
|
|
29
|
+
// The regex validation above already accepted path-like input; keep canonical navigation.
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const navigationUrl = new URL(canonicalUrl);
|
|
33
|
+
if (xsecToken) navigationUrl.searchParams.set("xsec_token", xsecToken);
|
|
34
|
+
if (xsecSource) navigationUrl.searchParams.set("xsec_source", xsecSource);
|
|
35
|
+
|
|
19
36
|
return {
|
|
20
37
|
userId,
|
|
21
|
-
canonicalUrl
|
|
38
|
+
canonicalUrl,
|
|
39
|
+
navigationUrl: navigationUrl.toString(),
|
|
40
|
+
xsecToken,
|
|
41
|
+
xsecSource,
|
|
22
42
|
};
|
|
23
43
|
}
|
|
24
44
|
|
|
@@ -35,9 +55,11 @@ export function parseXhsNoteUrl(input: string): XhsParsedNoteUrl {
|
|
|
35
55
|
|
|
36
56
|
// Extract xsec_token if present (internal use only)
|
|
37
57
|
let xsecToken: string | undefined;
|
|
58
|
+
let xsecSource: string | undefined;
|
|
38
59
|
try {
|
|
39
60
|
const urlObj = new URL(input.startsWith("http") ? input : `https://www.xiaohongshu.com${input}`);
|
|
40
61
|
xsecToken = urlObj.searchParams.get("xsec_token") ?? undefined;
|
|
62
|
+
xsecSource = urlObj.searchParams.get("xsec_source") ?? undefined;
|
|
41
63
|
} catch {
|
|
42
64
|
// ignore parse errors
|
|
43
65
|
}
|
|
@@ -46,6 +68,7 @@ export function parseXhsNoteUrl(input: string): XhsParsedNoteUrl {
|
|
|
46
68
|
noteId,
|
|
47
69
|
canonicalUrl: `https://www.xiaohongshu.com/explore/${noteId}`,
|
|
48
70
|
xsecToken,
|
|
71
|
+
xsecSource,
|
|
49
72
|
};
|
|
50
73
|
}
|
|
51
74
|
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { getAgentInternalCommandEntries } from "./agentInternalCommandEntries";
|
|
2
2
|
import { getDialogInternalCommandEntries } from "./dialogInternalCommandEntries";
|
|
3
|
+
import { getDocInternalCommandEntries } from "./docInternalCommandEntries";
|
|
3
4
|
import type { CommandEntry } from "./cliCommandTypes";
|
|
5
|
+
import { getMemoryInternalCommandEntries } from "./memoryInternalCommandEntries";
|
|
4
6
|
import { getSystemInternalCommandEntries } from "./systemInternalCommandEntries";
|
|
5
7
|
import { getWorkflowInternalCommandEntries } from "./workflowInternalCommandEntries";
|
|
6
8
|
|
|
@@ -8,6 +10,8 @@ export function getInternalCommandEntries(renderHelpText: () => string): Command
|
|
|
8
10
|
return [
|
|
9
11
|
...getAgentInternalCommandEntries(),
|
|
10
12
|
...getDialogInternalCommandEntries(),
|
|
13
|
+
...getDocInternalCommandEntries(),
|
|
14
|
+
...getMemoryInternalCommandEntries(),
|
|
11
15
|
...getWorkflowInternalCommandEntries(),
|
|
12
16
|
...getSystemInternalCommandEntries(renderHelpText),
|
|
13
17
|
];
|
package/machineCommands.ts
CHANGED
|
@@ -132,50 +132,34 @@ function detectLaunchableMachineInfo() {
|
|
|
132
132
|
return detectMachineInfo({ probeLaunchable: true });
|
|
133
133
|
}
|
|
134
134
|
|
|
135
|
-
function
|
|
136
|
-
const
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
if (haystack.includes("project-manager") || haystack.includes("项目经理")) return "pm";
|
|
145
|
-
return "codex";
|
|
135
|
+
function findTaskRowSubjectRef(runtimeContext: any) {
|
|
136
|
+
const subjectRefs = Array.isArray(runtimeContext?.subjectRefs) ? runtimeContext.subjectRefs : [];
|
|
137
|
+
for (const ref of subjectRefs) {
|
|
138
|
+
if (!ref || typeof ref !== "object" || Array.isArray(ref)) continue;
|
|
139
|
+
if (ref.kind !== "table-row") continue;
|
|
140
|
+
const id = typeof ref.id === "string" ? ref.id.trim() : "";
|
|
141
|
+
if (id) return id;
|
|
142
|
+
}
|
|
143
|
+
return "";
|
|
146
144
|
}
|
|
147
145
|
|
|
148
|
-
function
|
|
146
|
+
function buildTaskEvidencePrompt(args: {
|
|
149
147
|
agentKey: string;
|
|
150
148
|
agentConfig: any;
|
|
151
149
|
runtimeContext: any;
|
|
152
150
|
}) {
|
|
153
|
-
const
|
|
154
|
-
const rowDbKey = typeof taskRun?.rowDbKey === "string" ? taskRun.rowDbKey.trim() : "";
|
|
151
|
+
const rowDbKey = findTaskRowSubjectRef(args.runtimeContext);
|
|
155
152
|
if (!rowDbKey) return "";
|
|
156
|
-
const workItemId = typeof taskRun?.workItemId === "string" ? taskRun.workItemId.trim() : "";
|
|
157
|
-
const role = inferTaskRunRole(args.agentKey, args.agentConfig);
|
|
158
153
|
return [
|
|
159
|
-
"--- Nolo task
|
|
154
|
+
"--- Nolo task evidence context ---",
|
|
160
155
|
"This CLI runtime does not receive server-side function tools directly.",
|
|
161
|
-
"Use the
|
|
156
|
+
"Use the task row subjectRef and linked dialog/activity evidence as the durable task context.",
|
|
162
157
|
"Run commands from the repository root. The runner already provides server URL and auth in the environment.",
|
|
163
158
|
"Release boundary: after review passes, AI/reviewer/Codex may advance alpha for verification. Do not merge, push, or release main/release unless the human owner explicitly authorizes it in the current task context.",
|
|
164
|
-
"
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
? [
|
|
169
|
-
`Claim work item: bun packages/cli/index.ts task-run claim-work-item --row-dbkey ${JSON.stringify(rowDbKey)} --work-item-id ${JSON.stringify(workItemId)} --agent-key ${JSON.stringify(args.agentKey)} --role ${role}`,
|
|
170
|
-
`Set blocker: bun packages/cli/index.ts task-run set-blocker --row-dbkey ${JSON.stringify(rowDbKey)} --work-item-id ${JSON.stringify(workItemId)} --layer tool --code <CODE> --message <MESSAGE>`,
|
|
171
|
-
`Clear resolved blocker: bun packages/cli/index.ts task-run clear-blocker --row-dbkey ${JSON.stringify(rowDbKey)} --work-item-id ${JSON.stringify(workItemId)} --blocker-id <BLOCKER_ID>`,
|
|
172
|
-
`Submit outcome: bun packages/cli/index.ts task-run submit-outcome --row-dbkey ${JSON.stringify(rowDbKey)} --work-item-id ${JSON.stringify(workItemId)} --summary <SUMMARY>`,
|
|
173
|
-
`Request review: bun packages/cli/index.ts task-run request-review --row-dbkey ${JSON.stringify(rowDbKey)} --work-item-id ${JSON.stringify(workItemId)} --reviewer-agent-key <AGENT_KEY> --message <MESSAGE>`,
|
|
174
|
-
`Record review: bun packages/cli/index.ts task-run record-review --row-dbkey ${JSON.stringify(rowDbKey)} --work-item-id ${JSON.stringify(workItemId)} --review-status <passed|needs_changes|blocked> --reviewer-agent-key ${JSON.stringify(args.agentKey)} --findings <FINDINGS>`,
|
|
175
|
-
`Close work item: bun packages/cli/index.ts task-run close-work-item --row-dbkey ${JSON.stringify(rowDbKey)} --work-item-id ${JSON.stringify(workItemId)} --summary <SUMMARY>`,
|
|
176
|
-
]
|
|
177
|
-
: []),
|
|
178
|
-
"If a bridge command fails, report the exact command and error.",
|
|
159
|
+
"Handoff context: inspect activityRefs/latestActivityRef, dialog checkpoints, artifacts, commits, and test evidence. Use dialog read/search for exact evidence; do not infer completion from handoff text alone.",
|
|
160
|
+
`Read task row: bun packages/cli/index.ts table query --table meta-0e95801d90-NOLOTASKBOARD --row ${JSON.stringify(rowDbKey)} --include-activity --output json`,
|
|
161
|
+
"Then read linked activity dialog ids with: bun packages/cli/index.ts dialog read <dialogId>",
|
|
162
|
+
"Report progress, blockers, worktree, branch, commit/diff, tests, and unverified items in the dialog.",
|
|
179
163
|
].join("\n");
|
|
180
164
|
}
|
|
181
165
|
|
|
@@ -186,7 +170,7 @@ function buildConnectorCliPrompt(agentConfig: any, userInput: string, bridgeArgs
|
|
|
186
170
|
const policy = permissionPolicy ?? resolveMachineRunPermissionPolicy(agentConfig);
|
|
187
171
|
return [
|
|
188
172
|
typeof agentConfig?.prompt === "string" ? agentConfig.prompt.trim() : "",
|
|
189
|
-
bridgeArgs ?
|
|
173
|
+
bridgeArgs ? buildTaskEvidencePrompt({
|
|
190
174
|
agentKey: bridgeArgs.agentKey,
|
|
191
175
|
agentConfig,
|
|
192
176
|
runtimeContext: bridgeArgs.runtimeContext,
|