@sentry/junior 0.20.0 → 0.21.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/app.js +352 -78
- package/dist/{chunk-DTOS5CG4.js → chunk-N4ICA2BC.js} +59 -8
- package/dist/{chunk-VJLT6LLV.js → chunk-NRSP2MLC.js} +2 -2
- package/dist/{chunk-RBB2MZAN.js → chunk-XPXD3FCE.js} +23 -5
- package/dist/{chunk-LOTYK7IE.js → chunk-Z43DS7XN.js} +6 -2
- package/dist/cli/check.js +60 -3
- package/dist/cli/init.js +8 -3
- package/dist/cli/snapshot-warmup.js +3 -3
- package/dist/nitro.js +1 -1
- package/package.json +1 -1
package/dist/app.js
CHANGED
|
@@ -6,8 +6,9 @@ import {
|
|
|
6
6
|
loadSkillsByName,
|
|
7
7
|
logCapabilityCatalogLoadedOnce,
|
|
8
8
|
parseSkillInvocation
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-NRSP2MLC.js";
|
|
10
10
|
import {
|
|
11
|
+
SANDBOX_DATA_ROOT,
|
|
11
12
|
SANDBOX_SKILLS_ROOT,
|
|
12
13
|
SANDBOX_WORKSPACE_ROOT,
|
|
13
14
|
botConfig,
|
|
@@ -26,7 +27,7 @@ import {
|
|
|
26
27
|
sandboxSkillDir,
|
|
27
28
|
sandboxSkillFile,
|
|
28
29
|
toOptionalTrimmed
|
|
29
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-Z43DS7XN.js";
|
|
30
31
|
import {
|
|
31
32
|
CredentialUnavailableError,
|
|
32
33
|
buildOAuthTokenRequest,
|
|
@@ -38,6 +39,7 @@ import {
|
|
|
38
39
|
getPluginMcpProviders,
|
|
39
40
|
getPluginOAuthConfig,
|
|
40
41
|
getPluginProviders,
|
|
42
|
+
hasRequiredOAuthScope,
|
|
41
43
|
isPluginProvider,
|
|
42
44
|
isRecord,
|
|
43
45
|
logError,
|
|
@@ -55,15 +57,16 @@ import {
|
|
|
55
57
|
toOptionalString,
|
|
56
58
|
withContext,
|
|
57
59
|
withSpan
|
|
58
|
-
} from "./chunk-
|
|
60
|
+
} from "./chunk-N4ICA2BC.js";
|
|
59
61
|
import "./chunk-Z3YD6NHK.js";
|
|
60
62
|
import {
|
|
61
|
-
aboutPathCandidates,
|
|
62
63
|
discoverInstalledPluginPackageContent,
|
|
63
64
|
homeDir,
|
|
65
|
+
listReferenceFiles,
|
|
64
66
|
setPluginPackages,
|
|
65
|
-
soulPathCandidates
|
|
66
|
-
|
|
67
|
+
soulPathCandidates,
|
|
68
|
+
worldPathCandidates
|
|
69
|
+
} from "./chunk-XPXD3FCE.js";
|
|
67
70
|
import "./chunk-2KG3PWR4.js";
|
|
68
71
|
|
|
69
72
|
// src/app.ts
|
|
@@ -72,9 +75,12 @@ import { Hono } from "hono";
|
|
|
72
75
|
// src/handlers/diagnostics.ts
|
|
73
76
|
import { readFileSync } from "fs";
|
|
74
77
|
import path from "path";
|
|
75
|
-
function
|
|
78
|
+
function readDescriptionText() {
|
|
76
79
|
try {
|
|
77
|
-
const raw = readFileSync(
|
|
80
|
+
const raw = readFileSync(
|
|
81
|
+
path.join(homeDir(), "DESCRIPTION.md"),
|
|
82
|
+
"utf8"
|
|
83
|
+
).trim();
|
|
78
84
|
return raw || void 0;
|
|
79
85
|
} catch {
|
|
80
86
|
return void 0;
|
|
@@ -86,7 +92,7 @@ async function GET() {
|
|
|
86
92
|
return Response.json({
|
|
87
93
|
cwd: process.cwd(),
|
|
88
94
|
homeDir: homeDir(),
|
|
89
|
-
|
|
95
|
+
descriptionText: readDescriptionText(),
|
|
90
96
|
providers: getPluginProviders().map((plugin) => plugin.manifest.name),
|
|
91
97
|
skills: skills.map((skill) => ({
|
|
92
98
|
name: skill.name,
|
|
@@ -198,9 +204,9 @@ async function GET3() {
|
|
|
198
204
|
</head>
|
|
199
205
|
<body>
|
|
200
206
|
<h1>> junior</h1>`;
|
|
201
|
-
if (d?.
|
|
207
|
+
if (d?.descriptionText) {
|
|
202
208
|
html += `
|
|
203
|
-
<div class="subtitle">${escapeXml(String(d.
|
|
209
|
+
<div class="subtitle">${escapeXml(String(d.descriptionText))}</div>`;
|
|
204
210
|
}
|
|
205
211
|
html += `
|
|
206
212
|
<div class="section">
|
|
@@ -2298,6 +2304,17 @@ async function completeObject(params) {
|
|
|
2298
2304
|
};
|
|
2299
2305
|
}
|
|
2300
2306
|
|
|
2307
|
+
// src/chat/slack/message.ts
|
|
2308
|
+
function getSlackMessageTs(message) {
|
|
2309
|
+
if (message.id.endsWith(":message_changed_mention") && message.raw && typeof message.raw === "object") {
|
|
2310
|
+
const ts = message.raw.ts;
|
|
2311
|
+
if (typeof ts === "string" && ts.length > 0) {
|
|
2312
|
+
return ts;
|
|
2313
|
+
}
|
|
2314
|
+
}
|
|
2315
|
+
return message.id;
|
|
2316
|
+
}
|
|
2317
|
+
|
|
2301
2318
|
// src/chat/services/conversation-memory.ts
|
|
2302
2319
|
var CONTEXT_COMPACTION_TRIGGER_TOKENS = 9e3;
|
|
2303
2320
|
var CONTEXT_COMPACTION_TARGET_TOKENS = 7e3;
|
|
@@ -2572,7 +2589,7 @@ function createConversationMessageFromSdkMessage(entry) {
|
|
|
2572
2589
|
isBot: typeof entry.author.isBot === "boolean" ? entry.author.isBot : void 0
|
|
2573
2590
|
},
|
|
2574
2591
|
meta: {
|
|
2575
|
-
slackTs: entry
|
|
2592
|
+
slackTs: getSlackMessageTs(entry)
|
|
2576
2593
|
}
|
|
2577
2594
|
};
|
|
2578
2595
|
}
|
|
@@ -2651,6 +2668,7 @@ import { Agent } from "@mariozechner/pi-agent-core";
|
|
|
2651
2668
|
|
|
2652
2669
|
// src/chat/prompt.ts
|
|
2653
2670
|
import fs from "fs";
|
|
2671
|
+
import path2 from "path";
|
|
2654
2672
|
var DEFAULT_SOUL = "You are Junior, a practical and concise assistant.";
|
|
2655
2673
|
function getLoggedMarkdownFiles() {
|
|
2656
2674
|
const globalState = globalThis;
|
|
@@ -2698,8 +2716,8 @@ function loadSoul() {
|
|
|
2698
2716
|
);
|
|
2699
2717
|
return DEFAULT_SOUL;
|
|
2700
2718
|
}
|
|
2701
|
-
function
|
|
2702
|
-
return loadOptionalMarkdownFile(
|
|
2719
|
+
function loadWorld() {
|
|
2720
|
+
return loadOptionalMarkdownFile(worldPathCandidates(), "WORLD.md");
|
|
2703
2721
|
}
|
|
2704
2722
|
var JUNIOR_PERSONALITY = (() => {
|
|
2705
2723
|
try {
|
|
@@ -2716,17 +2734,17 @@ var JUNIOR_PERSONALITY = (() => {
|
|
|
2716
2734
|
return DEFAULT_SOUL;
|
|
2717
2735
|
}
|
|
2718
2736
|
})();
|
|
2719
|
-
var
|
|
2737
|
+
var JUNIOR_WORLD = (() => {
|
|
2720
2738
|
try {
|
|
2721
|
-
return
|
|
2739
|
+
return loadWorld();
|
|
2722
2740
|
} catch (error) {
|
|
2723
2741
|
logWarn(
|
|
2724
|
-
"
|
|
2742
|
+
"world_load_failed",
|
|
2725
2743
|
{},
|
|
2726
2744
|
{
|
|
2727
2745
|
"error.message": error instanceof Error ? error.message : String(error)
|
|
2728
2746
|
},
|
|
2729
|
-
"Failed to load
|
|
2747
|
+
"Failed to load WORLD.md; omitting world prompt context"
|
|
2730
2748
|
);
|
|
2731
2749
|
return null;
|
|
2732
2750
|
}
|
|
@@ -2846,6 +2864,25 @@ function baseSystemPrompt() {
|
|
|
2846
2864
|
"- When active skills are present, follow their instructions before default behavior."
|
|
2847
2865
|
].join("\n");
|
|
2848
2866
|
}
|
|
2867
|
+
function formatReferenceFilesSection() {
|
|
2868
|
+
const files = listReferenceFiles();
|
|
2869
|
+
if (files.length === 0) {
|
|
2870
|
+
return [];
|
|
2871
|
+
}
|
|
2872
|
+
const fileNames = files.map((filePath) => {
|
|
2873
|
+
const name = path2.basename(filePath);
|
|
2874
|
+
return `- ${escapeXml(name)} (${escapeXml(`${SANDBOX_DATA_ROOT}/${name}`)})`;
|
|
2875
|
+
});
|
|
2876
|
+
return [
|
|
2877
|
+
renderTag(
|
|
2878
|
+
"reference-files",
|
|
2879
|
+
[
|
|
2880
|
+
"Additional reference documents available in the sandbox. Read them with `readFile` when relevant.",
|
|
2881
|
+
...fileNames
|
|
2882
|
+
].join("\n")
|
|
2883
|
+
)
|
|
2884
|
+
];
|
|
2885
|
+
}
|
|
2849
2886
|
function buildSystemPrompt(params) {
|
|
2850
2887
|
const {
|
|
2851
2888
|
availableSkills,
|
|
@@ -2857,7 +2894,8 @@ function buildSystemPrompt(params) {
|
|
|
2857
2894
|
artifactState,
|
|
2858
2895
|
configuration,
|
|
2859
2896
|
relevantConfigurationKeys,
|
|
2860
|
-
runtimeMetadata
|
|
2897
|
+
runtimeMetadata,
|
|
2898
|
+
threadParticipants
|
|
2861
2899
|
} = params;
|
|
2862
2900
|
const assistantSection = renderIdentityBlock("assistant", {
|
|
2863
2901
|
user_name: assistant?.userName ?? botConfig.userName,
|
|
@@ -2913,22 +2951,43 @@ function buildSystemPrompt(params) {
|
|
|
2913
2951
|
JUNIOR_PERSONALITY.trim()
|
|
2914
2952
|
].join("\n")
|
|
2915
2953
|
),
|
|
2916
|
-
...
|
|
2954
|
+
...JUNIOR_WORLD ? [
|
|
2917
2955
|
renderTag(
|
|
2918
|
-
"
|
|
2956
|
+
"world",
|
|
2919
2957
|
[
|
|
2920
|
-
"Use this as the assistant's
|
|
2958
|
+
"Use this as the assistant's operational/domain context.",
|
|
2921
2959
|
"",
|
|
2922
|
-
|
|
2960
|
+
JUNIOR_WORLD.trim()
|
|
2923
2961
|
].join("\n")
|
|
2924
2962
|
)
|
|
2925
2963
|
] : [],
|
|
2964
|
+
...formatReferenceFilesSection(),
|
|
2926
2965
|
renderTag(
|
|
2927
2966
|
"identity-context",
|
|
2928
2967
|
[
|
|
2929
2968
|
"Use these blocks as authoritative metadata for identity questions.",
|
|
2930
2969
|
assistantSection,
|
|
2931
|
-
requesterSection
|
|
2970
|
+
requesterSection,
|
|
2971
|
+
...threadParticipants && threadParticipants.length > 0 ? [
|
|
2972
|
+
renderTag(
|
|
2973
|
+
"thread-participants",
|
|
2974
|
+
[
|
|
2975
|
+
"Known participants in this thread. When you mention one of these people, use the provided Slack mention token exactly as `<@USERID>` and do not write a bare `@name` form.",
|
|
2976
|
+
...threadParticipants.map((p) => {
|
|
2977
|
+
const parts = [];
|
|
2978
|
+
if (p.userId) {
|
|
2979
|
+
parts.push(`user_id: ${escapeXml(p.userId)}`);
|
|
2980
|
+
parts.push(`slack_mention: <@${p.userId}>`);
|
|
2981
|
+
}
|
|
2982
|
+
if (p.userName)
|
|
2983
|
+
parts.push(`user_name: ${escapeXml(p.userName)}`);
|
|
2984
|
+
if (p.fullName)
|
|
2985
|
+
parts.push(`full_name: ${escapeXml(p.fullName)}`);
|
|
2986
|
+
return `- ${parts.join(", ")}`;
|
|
2987
|
+
})
|
|
2988
|
+
].join("\n")
|
|
2989
|
+
)
|
|
2990
|
+
] : []
|
|
2932
2991
|
].join("\n")
|
|
2933
2992
|
),
|
|
2934
2993
|
renderTag(
|
|
@@ -3827,7 +3886,8 @@ async function handleOAuthStartCommand(args, deps) {
|
|
|
3827
3886
|
}
|
|
3828
3887
|
if (deps.requesterId && deps.userTokenStore) {
|
|
3829
3888
|
const stored = await deps.userTokenStore.get(deps.requesterId, provider);
|
|
3830
|
-
|
|
3889
|
+
const providerConfig = getPluginOAuthConfig(provider);
|
|
3890
|
+
if (stored && (stored.expiresAt === void 0 || stored.expiresAt > Date.now()) && hasRequiredOAuthScope(stored.scope, providerConfig?.scope)) {
|
|
3831
3891
|
const providerLabel = formatProviderLabel(provider);
|
|
3832
3892
|
return commandResult({
|
|
3833
3893
|
stdout: {
|
|
@@ -3982,12 +4042,12 @@ async function maybeExecuteJrRpcCustomCommand(command, deps) {
|
|
|
3982
4042
|
|
|
3983
4043
|
// src/chat/sandbox/skill-sandbox.ts
|
|
3984
4044
|
import fs2 from "fs/promises";
|
|
3985
|
-
import
|
|
4045
|
+
import path3 from "path";
|
|
3986
4046
|
var MAX_SKILL_FILE_BYTES = 256 * 1024;
|
|
3987
4047
|
var DEFAULT_MAX_SKILL_FILE_CHARS = 2e4;
|
|
3988
4048
|
var DEFAULT_MAX_SKILL_LIST_ENTRIES = 200;
|
|
3989
4049
|
function normalizePathForOutput(value) {
|
|
3990
|
-
return value.split(
|
|
4050
|
+
return value.split(path3.sep).join("/");
|
|
3991
4051
|
}
|
|
3992
4052
|
function normalizeSkillName(value) {
|
|
3993
4053
|
return value.trim().toLowerCase();
|
|
@@ -3996,12 +4056,12 @@ function resolvePathWithinRoot(root, relativePath) {
|
|
|
3996
4056
|
if (!relativePath.trim()) {
|
|
3997
4057
|
throw new Error("Path must not be empty.");
|
|
3998
4058
|
}
|
|
3999
|
-
if (
|
|
4059
|
+
if (path3.isAbsolute(relativePath)) {
|
|
4000
4060
|
throw new Error("Absolute paths are not allowed.");
|
|
4001
4061
|
}
|
|
4002
|
-
const resolvedRoot =
|
|
4003
|
-
const resolvedPath =
|
|
4004
|
-
if (resolvedPath !== resolvedRoot && !resolvedPath.startsWith(`${resolvedRoot}${
|
|
4062
|
+
const resolvedRoot = path3.resolve(root);
|
|
4063
|
+
const resolvedPath = path3.resolve(resolvedRoot, relativePath);
|
|
4064
|
+
if (resolvedPath !== resolvedRoot && !resolvedPath.startsWith(`${resolvedRoot}${path3.sep}`)) {
|
|
4005
4065
|
throw new Error("Path escapes the skill directory.");
|
|
4006
4066
|
}
|
|
4007
4067
|
return resolvedPath;
|
|
@@ -4081,7 +4141,7 @@ var SkillSandbox = class {
|
|
|
4081
4141
|
1,
|
|
4082
4142
|
Math.min(params.maxEntries ?? DEFAULT_MAX_SKILL_LIST_ENTRIES, 1e3)
|
|
4083
4143
|
);
|
|
4084
|
-
const root =
|
|
4144
|
+
const root = path3.resolve(skill.skillPath);
|
|
4085
4145
|
const targetDirectory = resolvePathWithinRoot(root, directory);
|
|
4086
4146
|
const targetStats = await fs2.stat(targetDirectory);
|
|
4087
4147
|
if (!targetStats.isDirectory()) {
|
|
@@ -4097,9 +4157,9 @@ var SkillSandbox = class {
|
|
|
4097
4157
|
});
|
|
4098
4158
|
children.sort((a, b) => a.name.localeCompare(b.name));
|
|
4099
4159
|
for (const child of children) {
|
|
4100
|
-
const absolutePath =
|
|
4160
|
+
const absolutePath = path3.join(currentDirectory, child.name);
|
|
4101
4161
|
const relativePath = normalizePathForOutput(
|
|
4102
|
-
|
|
4162
|
+
path3.relative(root, absolutePath)
|
|
4103
4163
|
);
|
|
4104
4164
|
if (!relativePath || relativePath.startsWith("..")) {
|
|
4105
4165
|
continue;
|
|
@@ -4122,7 +4182,7 @@ var SkillSandbox = class {
|
|
|
4122
4182
|
}
|
|
4123
4183
|
}
|
|
4124
4184
|
const relativeDirectory = normalizePathForOutput(
|
|
4125
|
-
|
|
4185
|
+
path3.relative(root, targetDirectory) || "."
|
|
4126
4186
|
);
|
|
4127
4187
|
return {
|
|
4128
4188
|
skillName: skill.name,
|
|
@@ -4137,7 +4197,7 @@ var SkillSandbox = class {
|
|
|
4137
4197
|
1,
|
|
4138
4198
|
Math.min(params.maxChars ?? DEFAULT_MAX_SKILL_FILE_CHARS, 1e5)
|
|
4139
4199
|
);
|
|
4140
|
-
const root =
|
|
4200
|
+
const root = path3.resolve(skill.skillPath);
|
|
4141
4201
|
const targetPath = resolvePathWithinRoot(root, params.filePath);
|
|
4142
4202
|
const stats = await fs2.stat(targetPath);
|
|
4143
4203
|
if (!stats.isFile()) {
|
|
@@ -4152,7 +4212,7 @@ var SkillSandbox = class {
|
|
|
4152
4212
|
const truncated = raw.length > maxChars;
|
|
4153
4213
|
return {
|
|
4154
4214
|
skillName: skill.name,
|
|
4155
|
-
path: normalizePathForOutput(
|
|
4215
|
+
path: normalizePathForOutput(path3.relative(root, targetPath)),
|
|
4156
4216
|
content: truncated ? raw.slice(0, maxChars) : raw,
|
|
4157
4217
|
truncated
|
|
4158
4218
|
};
|
|
@@ -4726,7 +4786,7 @@ function createBashTool() {
|
|
|
4726
4786
|
}
|
|
4727
4787
|
|
|
4728
4788
|
// src/chat/tools/sandbox/attach-file.ts
|
|
4729
|
-
import
|
|
4789
|
+
import path4 from "path";
|
|
4730
4790
|
import { Type as Type2 } from "@sinclair/typebox";
|
|
4731
4791
|
var MAX_ATTACH_FILE_BYTES = 10 * 1024 * 1024;
|
|
4732
4792
|
var MIME_BY_EXTENSION = {
|
|
@@ -4748,20 +4808,20 @@ function normalizeSandboxPath(inputPath) {
|
|
|
4748
4808
|
if (!trimmed) {
|
|
4749
4809
|
throw new Error("path is required");
|
|
4750
4810
|
}
|
|
4751
|
-
if (
|
|
4811
|
+
if (path4.posix.isAbsolute(trimmed)) {
|
|
4752
4812
|
return trimmed;
|
|
4753
4813
|
}
|
|
4754
|
-
return
|
|
4814
|
+
return path4.posix.join(SANDBOX_WORKSPACE_ROOT, trimmed);
|
|
4755
4815
|
}
|
|
4756
4816
|
function sanitizeFilename(value, fallbackPath) {
|
|
4757
4817
|
const candidate = (value ?? "").trim();
|
|
4758
4818
|
if (candidate) {
|
|
4759
|
-
const base =
|
|
4819
|
+
const base = path4.posix.basename(candidate);
|
|
4760
4820
|
if (base && base !== "." && base !== "..") {
|
|
4761
4821
|
return base;
|
|
4762
4822
|
}
|
|
4763
4823
|
}
|
|
4764
|
-
const derived =
|
|
4824
|
+
const derived = path4.posix.basename(fallbackPath);
|
|
4765
4825
|
if (derived && derived !== "." && derived !== "..") {
|
|
4766
4826
|
return derived;
|
|
4767
4827
|
}
|
|
@@ -4772,7 +4832,7 @@ function inferMimeType(filename, explicitMimeType) {
|
|
|
4772
4832
|
if (explicit) {
|
|
4773
4833
|
return explicit;
|
|
4774
4834
|
}
|
|
4775
|
-
const ext =
|
|
4835
|
+
const ext = path4.extname(filename).toLowerCase();
|
|
4776
4836
|
return MIME_BY_EXTENSION[ext] ?? "application/octet-stream";
|
|
4777
4837
|
}
|
|
4778
4838
|
async function detectMimeType(sandbox, targetPath) {
|
|
@@ -4819,7 +4879,7 @@ function createAttachFileTool(sandbox, hooks = {}) {
|
|
|
4819
4879
|
const fileBuffer = await sandbox.readFileToBuffer({ path: targetPath });
|
|
4820
4880
|
if (!fileBuffer) {
|
|
4821
4881
|
const generatedFile = hooks.getGeneratedFile?.(
|
|
4822
|
-
|
|
4882
|
+
path4.posix.basename(targetPath)
|
|
4823
4883
|
);
|
|
4824
4884
|
if (generatedFile) {
|
|
4825
4885
|
hooks.onGeneratedFiles?.([generatedFile]);
|
|
@@ -7332,7 +7392,7 @@ function logAssistantStatusFailure(status, error) {
|
|
|
7332
7392
|
|
|
7333
7393
|
// src/chat/sandbox/skill-sync.ts
|
|
7334
7394
|
import fs3 from "fs/promises";
|
|
7335
|
-
import
|
|
7395
|
+
import path5 from "path";
|
|
7336
7396
|
|
|
7337
7397
|
// src/chat/sandbox/eval-gh-stub.ts
|
|
7338
7398
|
function buildEvalGitHubCliStub() {
|
|
@@ -7601,7 +7661,7 @@ fallbackToRealGh();
|
|
|
7601
7661
|
|
|
7602
7662
|
// src/chat/sandbox/skill-sync.ts
|
|
7603
7663
|
function toPosixRelative(base, absolute) {
|
|
7604
|
-
return
|
|
7664
|
+
return path5.relative(base, absolute).split(path5.sep).join("/");
|
|
7605
7665
|
}
|
|
7606
7666
|
async function listFilesRecursive(root) {
|
|
7607
7667
|
const queue = [root];
|
|
@@ -7611,7 +7671,7 @@ async function listFilesRecursive(root) {
|
|
|
7611
7671
|
const entries = await fs3.readdir(dir, { withFileTypes: true });
|
|
7612
7672
|
entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
7613
7673
|
for (const entry of entries) {
|
|
7614
|
-
const absolute =
|
|
7674
|
+
const absolute = path5.join(dir, entry.name);
|
|
7615
7675
|
if (entry.isDirectory()) {
|
|
7616
7676
|
queue.push(absolute);
|
|
7617
7677
|
} else if (entry.isFile()) {
|
|
@@ -7621,7 +7681,7 @@ async function listFilesRecursive(root) {
|
|
|
7621
7681
|
}
|
|
7622
7682
|
return files;
|
|
7623
7683
|
}
|
|
7624
|
-
async function buildSkillSyncFiles(availableSkills, runtimeBinDir) {
|
|
7684
|
+
async function buildSkillSyncFiles(availableSkills, runtimeBinDir, referenceFiles) {
|
|
7625
7685
|
const filesToWrite = [];
|
|
7626
7686
|
const index = {
|
|
7627
7687
|
skills: []
|
|
@@ -7648,6 +7708,15 @@ async function buildSkillSyncFiles(availableSkills, runtimeBinDir) {
|
|
|
7648
7708
|
path: `${SANDBOX_SKILLS_ROOT}/index.json`,
|
|
7649
7709
|
content: Buffer.from(JSON.stringify(index), "utf8")
|
|
7650
7710
|
});
|
|
7711
|
+
if (referenceFiles && referenceFiles.length > 0) {
|
|
7712
|
+
for (const absoluteFile of referenceFiles) {
|
|
7713
|
+
const fileName = path5.basename(absoluteFile);
|
|
7714
|
+
filesToWrite.push({
|
|
7715
|
+
path: `${SANDBOX_DATA_ROOT}/${fileName}`,
|
|
7716
|
+
content: await fs3.readFile(absoluteFile)
|
|
7717
|
+
});
|
|
7718
|
+
}
|
|
7719
|
+
}
|
|
7651
7720
|
if (process.env.EVAL_ENABLE_TEST_CREDENTIALS === "1") {
|
|
7652
7721
|
filesToWrite.push({
|
|
7653
7722
|
path: `${runtimeBinDir}/gh`,
|
|
@@ -7659,7 +7728,7 @@ async function buildSkillSyncFiles(availableSkills, runtimeBinDir) {
|
|
|
7659
7728
|
function collectDirectories(filesToWrite, workspaceRoot) {
|
|
7660
7729
|
const directoriesToEnsure = /* @__PURE__ */ new Set();
|
|
7661
7730
|
for (const file of filesToWrite) {
|
|
7662
|
-
const normalizedPath =
|
|
7731
|
+
const normalizedPath = path5.posix.normalize(file.path);
|
|
7663
7732
|
const parts = normalizedPath.split("/").filter(Boolean);
|
|
7664
7733
|
let current = "";
|
|
7665
7734
|
for (let index = 0; index < parts.length - 1; index += 1) {
|
|
@@ -7672,25 +7741,41 @@ function collectDirectories(filesToWrite, workspaceRoot) {
|
|
|
7672
7741
|
).sort((a, b) => a.length - b.length);
|
|
7673
7742
|
}
|
|
7674
7743
|
function resolveHostSkillPath(availableSkills, sandboxPath) {
|
|
7675
|
-
const normalizedPath =
|
|
7744
|
+
const normalizedPath = path5.posix.normalize(sandboxPath.trim());
|
|
7676
7745
|
for (const skill of availableSkills) {
|
|
7677
7746
|
const virtualRoot = sandboxSkillDir(skill.name);
|
|
7678
7747
|
if (normalizedPath !== virtualRoot && !normalizedPath.startsWith(`${virtualRoot}/`)) {
|
|
7679
7748
|
continue;
|
|
7680
7749
|
}
|
|
7681
|
-
const relativePath =
|
|
7750
|
+
const relativePath = path5.posix.relative(virtualRoot, normalizedPath);
|
|
7682
7751
|
if (!relativePath || relativePath.startsWith("../")) {
|
|
7683
7752
|
return null;
|
|
7684
7753
|
}
|
|
7685
|
-
const hostRoot =
|
|
7686
|
-
const hostPath =
|
|
7687
|
-
if (hostPath !== hostRoot && !hostPath.startsWith(`${hostRoot}${
|
|
7754
|
+
const hostRoot = path5.resolve(skill.skillPath);
|
|
7755
|
+
const hostPath = path5.resolve(hostRoot, ...relativePath.split("/"));
|
|
7756
|
+
if (hostPath !== hostRoot && !hostPath.startsWith(`${hostRoot}${path5.sep}`)) {
|
|
7688
7757
|
return null;
|
|
7689
7758
|
}
|
|
7690
7759
|
return hostPath;
|
|
7691
7760
|
}
|
|
7692
7761
|
return null;
|
|
7693
7762
|
}
|
|
7763
|
+
function resolveHostDataPath(referenceFiles, sandboxPath) {
|
|
7764
|
+
const normalizedPath = path5.posix.normalize(sandboxPath.trim());
|
|
7765
|
+
if (normalizedPath !== SANDBOX_DATA_ROOT && !normalizedPath.startsWith(`${SANDBOX_DATA_ROOT}/`)) {
|
|
7766
|
+
return null;
|
|
7767
|
+
}
|
|
7768
|
+
const relativePath = path5.posix.relative(SANDBOX_DATA_ROOT, normalizedPath);
|
|
7769
|
+
if (!relativePath || relativePath.startsWith("../") || relativePath.includes("/")) {
|
|
7770
|
+
return null;
|
|
7771
|
+
}
|
|
7772
|
+
for (const hostFile of referenceFiles) {
|
|
7773
|
+
if (path5.basename(hostFile) === relativePath) {
|
|
7774
|
+
return hostFile;
|
|
7775
|
+
}
|
|
7776
|
+
}
|
|
7777
|
+
return null;
|
|
7778
|
+
}
|
|
7694
7779
|
function isHostFileMissingError(error) {
|
|
7695
7780
|
return Boolean(
|
|
7696
7781
|
error && typeof error === "object" && error.code === "ENOENT"
|
|
@@ -7707,7 +7792,8 @@ async function syncSkillsToSandbox(params) {
|
|
|
7707
7792
|
async () => {
|
|
7708
7793
|
const filesToWrite = await buildSkillSyncFiles(
|
|
7709
7794
|
params.skills,
|
|
7710
|
-
params.runtimeBinDir
|
|
7795
|
+
params.runtimeBinDir,
|
|
7796
|
+
params.referenceFiles
|
|
7711
7797
|
);
|
|
7712
7798
|
const bytesWritten = filesToWrite.reduce(
|
|
7713
7799
|
(total, file) => total + file.content.length,
|
|
@@ -7841,6 +7927,7 @@ function createSandboxSessionManager(options) {
|
|
|
7841
7927
|
let sandbox = null;
|
|
7842
7928
|
let sandboxIdHint = options?.sandboxId;
|
|
7843
7929
|
let availableSkills = [];
|
|
7930
|
+
let availableReferenceFiles = [];
|
|
7844
7931
|
let toolExecutors;
|
|
7845
7932
|
const timeoutMs = options?.timeoutMs ?? 1e3 * 60 * 30;
|
|
7846
7933
|
const traceContext = options?.traceContext ?? {};
|
|
@@ -7881,6 +7968,7 @@ function createSandboxSessionManager(options) {
|
|
|
7881
7968
|
await syncSkillsToSandbox({
|
|
7882
7969
|
sandbox: targetSandbox,
|
|
7883
7970
|
skills: availableSkills,
|
|
7971
|
+
referenceFiles: availableReferenceFiles,
|
|
7884
7972
|
withSpan: withSandboxSpan,
|
|
7885
7973
|
runtimeBinDir: SANDBOX_RUNTIME_BIN_DIR
|
|
7886
7974
|
});
|
|
@@ -8281,6 +8369,9 @@ function createSandboxSessionManager(options) {
|
|
|
8281
8369
|
configureSkills(skills) {
|
|
8282
8370
|
availableSkills = [...skills];
|
|
8283
8371
|
},
|
|
8372
|
+
configureReferenceFiles(files) {
|
|
8373
|
+
availableReferenceFiles = [...files];
|
|
8374
|
+
},
|
|
8284
8375
|
getSandboxId() {
|
|
8285
8376
|
return sandbox?.sandboxId ?? sandboxIdHint;
|
|
8286
8377
|
},
|
|
@@ -8352,6 +8443,7 @@ function createSandboxWorkspace(sandbox) {
|
|
|
8352
8443
|
}
|
|
8353
8444
|
function createSandboxExecutor(options) {
|
|
8354
8445
|
let availableSkills = [];
|
|
8446
|
+
let referenceFiles = [];
|
|
8355
8447
|
const traceContext = options?.traceContext ?? {};
|
|
8356
8448
|
const sessionManager = createSandboxSessionManager({
|
|
8357
8449
|
sandboxId: options?.sandboxId,
|
|
@@ -8439,10 +8531,10 @@ function createSandboxExecutor(options) {
|
|
|
8439
8531
|
throw new Error("path is required");
|
|
8440
8532
|
}
|
|
8441
8533
|
if (!sessionManager.getSandboxId()) {
|
|
8442
|
-
const
|
|
8443
|
-
if (
|
|
8534
|
+
const hostPath = resolveHostSkillPath(availableSkills, filePath) ?? resolveHostDataPath(referenceFiles, filePath);
|
|
8535
|
+
if (hostPath) {
|
|
8444
8536
|
try {
|
|
8445
|
-
const content = await fs4.readFile(
|
|
8537
|
+
const content = await fs4.readFile(hostPath, "utf8");
|
|
8446
8538
|
setSpanAttributes({
|
|
8447
8539
|
"app.sandbox.path.length": filePath.length,
|
|
8448
8540
|
"app.sandbox.read.bytes": Buffer.byteLength(content, "utf8"),
|
|
@@ -8553,6 +8645,10 @@ function createSandboxExecutor(options) {
|
|
|
8553
8645
|
availableSkills = [...skills];
|
|
8554
8646
|
sessionManager.configureSkills(skills);
|
|
8555
8647
|
},
|
|
8648
|
+
configureReferenceFiles(files) {
|
|
8649
|
+
referenceFiles = [...files];
|
|
8650
|
+
sessionManager.configureReferenceFiles(files);
|
|
8651
|
+
},
|
|
8556
8652
|
getSandboxId() {
|
|
8557
8653
|
return sessionManager.getSandboxId();
|
|
8558
8654
|
},
|
|
@@ -8581,7 +8677,7 @@ function shouldEmitDevAgentTrace() {
|
|
|
8581
8677
|
function buildToolStatus(toolName, input) {
|
|
8582
8678
|
const obj = input && typeof input === "object" ? input : void 0;
|
|
8583
8679
|
const command = obj ? compactStatusCommand(obj.command) : void 0;
|
|
8584
|
-
const
|
|
8680
|
+
const path7 = obj ? compactStatusPath(obj.path) : void 0;
|
|
8585
8681
|
const filename = obj ? compactStatusFilename(obj.path) : void 0;
|
|
8586
8682
|
const query = obj ? compactStatusText(obj.query, 70) : void 0;
|
|
8587
8683
|
const domain = obj ? extractStatusUrlDomain(obj.url) : void 0;
|
|
@@ -8596,8 +8692,8 @@ function buildToolStatus(toolName, input) {
|
|
|
8596
8692
|
if (filename && toolName === "writeFile") {
|
|
8597
8693
|
return makeAssistantStatus("updating", filename);
|
|
8598
8694
|
}
|
|
8599
|
-
if (
|
|
8600
|
-
return makeAssistantStatus("updating",
|
|
8695
|
+
if (path7 && toolName === "writeFile") {
|
|
8696
|
+
return makeAssistantStatus("updating", path7);
|
|
8601
8697
|
}
|
|
8602
8698
|
if (skillName && toolName === "loadSkill") {
|
|
8603
8699
|
return makeAssistantStatus("loading", skillName);
|
|
@@ -9499,6 +9595,7 @@ async function generateAssistantReply(messageText, context = {}) {
|
|
|
9499
9595
|
});
|
|
9500
9596
|
const currentSandboxExecutor = sandboxExecutor;
|
|
9501
9597
|
sandboxExecutor.configureSkills(availableSkills);
|
|
9598
|
+
sandboxExecutor.configureReferenceFiles(listReferenceFiles());
|
|
9502
9599
|
let sandboxPromise;
|
|
9503
9600
|
let sandboxPromiseId;
|
|
9504
9601
|
const clearSandboxPromise = () => {
|
|
@@ -9677,7 +9774,8 @@ async function generateAssistantReply(messageText, context = {}) {
|
|
|
9677
9774
|
activeSkills,
|
|
9678
9775
|
invokedSkill
|
|
9679
9776
|
),
|
|
9680
|
-
runtimeMetadata: getRuntimeMetadata()
|
|
9777
|
+
runtimeMetadata: getRuntimeMetadata(),
|
|
9778
|
+
threadParticipants: context.threadParticipants
|
|
9681
9779
|
});
|
|
9682
9780
|
const userContentParts = [{ type: "text", text: userTurnText }];
|
|
9683
9781
|
for (const attachment of context.userAttachments ?? []) {
|
|
@@ -10560,8 +10658,8 @@ async function GET4(request, provider, waitUntil) {
|
|
|
10560
10658
|
|
|
10561
10659
|
// src/chat/slack/app-home.ts
|
|
10562
10660
|
import fs5 from "fs";
|
|
10563
|
-
import
|
|
10564
|
-
var
|
|
10661
|
+
import path6 from "path";
|
|
10662
|
+
var DEFAULT_DESCRIPTION_TEXT = "I help your team investigate, summarize, and act on work in Slack.";
|
|
10565
10663
|
var MAX_HOME_SKILLS = 6;
|
|
10566
10664
|
var MAX_SECTION_TEXT_CHARS = 3e3;
|
|
10567
10665
|
var HIDDEN_HOME_SKILLS = /* @__PURE__ */ new Set(["jr-rpc"]);
|
|
@@ -10571,16 +10669,16 @@ function clampSectionText(text) {
|
|
|
10571
10669
|
}
|
|
10572
10670
|
return `${text.slice(0, MAX_SECTION_TEXT_CHARS - 1)}\u2026`;
|
|
10573
10671
|
}
|
|
10574
|
-
function
|
|
10575
|
-
const
|
|
10672
|
+
function loadDescriptionText() {
|
|
10673
|
+
const descriptionPath = path6.join(homeDir(), "DESCRIPTION.md");
|
|
10576
10674
|
try {
|
|
10577
|
-
const raw = fs5.readFileSync(
|
|
10675
|
+
const raw = fs5.readFileSync(descriptionPath, "utf8").trim();
|
|
10578
10676
|
if (raw.length > 0) {
|
|
10579
10677
|
return clampSectionText(raw);
|
|
10580
10678
|
}
|
|
10581
10679
|
} catch {
|
|
10582
10680
|
}
|
|
10583
|
-
return
|
|
10681
|
+
return DEFAULT_DESCRIPTION_TEXT;
|
|
10584
10682
|
}
|
|
10585
10683
|
async function buildSkillsSummaryText() {
|
|
10586
10684
|
const skills = (await discoverSkills()).filter(
|
|
@@ -10600,7 +10698,10 @@ async function buildSkillsSummaryText() {
|
|
|
10600
10698
|
}
|
|
10601
10699
|
async function hasConnectedAccount(userId, plugin, userTokenStore) {
|
|
10602
10700
|
if (plugin.manifest.credentials?.type === "oauth-bearer") {
|
|
10603
|
-
|
|
10701
|
+
const stored = await userTokenStore.get(userId, plugin.manifest.name);
|
|
10702
|
+
return Boolean(
|
|
10703
|
+
stored && hasRequiredOAuthScope(stored.scope, plugin.manifest.oauth?.scope)
|
|
10704
|
+
);
|
|
10604
10705
|
}
|
|
10605
10706
|
if (plugin.manifest.mcp) {
|
|
10606
10707
|
return Boolean(
|
|
@@ -10611,7 +10712,7 @@ async function hasConnectedAccount(userId, plugin, userTokenStore) {
|
|
|
10611
10712
|
}
|
|
10612
10713
|
async function buildHomeView(userId, userTokenStore) {
|
|
10613
10714
|
const runtimeMetadata = getRuntimeMetadata();
|
|
10614
|
-
const
|
|
10715
|
+
const descriptionText = loadDescriptionText();
|
|
10615
10716
|
const skillsSummaryText = await buildSkillsSummaryText();
|
|
10616
10717
|
const providers = getPluginProviders();
|
|
10617
10718
|
const connectedSections = [];
|
|
@@ -10656,7 +10757,7 @@ ${plugin.manifest.description}`
|
|
|
10656
10757
|
type: "section",
|
|
10657
10758
|
text: {
|
|
10658
10759
|
type: "mrkdwn",
|
|
10659
|
-
text:
|
|
10760
|
+
text: descriptionText
|
|
10660
10761
|
}
|
|
10661
10762
|
},
|
|
10662
10763
|
{ type: "divider" },
|
|
@@ -10863,7 +10964,10 @@ async function GET5(request, provider, waitUntil) {
|
|
|
10863
10964
|
const tokenData = await tokenResponse.json();
|
|
10864
10965
|
let parsedTokenResponse;
|
|
10865
10966
|
try {
|
|
10866
|
-
parsedTokenResponse = parseOAuthTokenResponse(
|
|
10967
|
+
parsedTokenResponse = parseOAuthTokenResponse(
|
|
10968
|
+
tokenData,
|
|
10969
|
+
providerConfig.scope
|
|
10970
|
+
);
|
|
10867
10971
|
} catch {
|
|
10868
10972
|
return htmlErrorResponse(
|
|
10869
10973
|
"Connection failed",
|
|
@@ -10871,6 +10975,13 @@ async function GET5(request, provider, waitUntil) {
|
|
|
10871
10975
|
500
|
|
10872
10976
|
);
|
|
10873
10977
|
}
|
|
10978
|
+
if (!hasRequiredOAuthScope(parsedTokenResponse.scope, providerConfig.scope)) {
|
|
10979
|
+
return htmlErrorResponse(
|
|
10980
|
+
"Connection failed",
|
|
10981
|
+
`The ${providerLabel} authorization did not grant the access Junior requires. Return to Slack and ask Junior to connect your ${providerLabel} account again.`,
|
|
10982
|
+
400
|
|
10983
|
+
);
|
|
10984
|
+
}
|
|
10874
10985
|
const userTokenStore = createUserTokenStore();
|
|
10875
10986
|
await userTokenStore.set(stored.userId, provider, parsedTokenResponse);
|
|
10876
10987
|
waitUntil(async () => {
|
|
@@ -12383,6 +12494,19 @@ function getExecutionFailureReason(reply) {
|
|
|
12383
12494
|
}
|
|
12384
12495
|
return "empty assistant turn";
|
|
12385
12496
|
}
|
|
12497
|
+
function buildParticipants(messages) {
|
|
12498
|
+
const seen = /* @__PURE__ */ new Set();
|
|
12499
|
+
const participants = [];
|
|
12500
|
+
for (const message of messages) {
|
|
12501
|
+
const { userId, userName, fullName } = message.author ?? {};
|
|
12502
|
+
if (!userId || message.author?.isBot) continue;
|
|
12503
|
+
if (!seen.has(userId)) {
|
|
12504
|
+
seen.add(userId);
|
|
12505
|
+
participants.push({ userId, userName, fullName });
|
|
12506
|
+
}
|
|
12507
|
+
}
|
|
12508
|
+
return participants;
|
|
12509
|
+
}
|
|
12386
12510
|
function createReplyToThread(deps) {
|
|
12387
12511
|
return async function replyToThread(thread, message, options = {}) {
|
|
12388
12512
|
if (message.author.isMe) {
|
|
@@ -12425,6 +12549,7 @@ function createReplyToThread(deps) {
|
|
|
12425
12549
|
runId
|
|
12426
12550
|
}
|
|
12427
12551
|
});
|
|
12552
|
+
const slackMessageTs = getSlackMessageTs(message);
|
|
12428
12553
|
const turnId = buildDeterministicTurnId(message.id);
|
|
12429
12554
|
startActiveTurn({
|
|
12430
12555
|
conversation: preparedState.conversation,
|
|
@@ -12477,7 +12602,7 @@ function createReplyToThread(deps) {
|
|
|
12477
12602
|
channelId,
|
|
12478
12603
|
runId,
|
|
12479
12604
|
conversation: preparedState.conversation,
|
|
12480
|
-
messageTs:
|
|
12605
|
+
messageTs: slackMessageTs
|
|
12481
12606
|
}
|
|
12482
12607
|
);
|
|
12483
12608
|
const progress = createProgressReporter({
|
|
@@ -12541,6 +12666,9 @@ function createReplyToThread(deps) {
|
|
|
12541
12666
|
let shouldPersistFailureState = true;
|
|
12542
12667
|
try {
|
|
12543
12668
|
const toolChannelId = preparedState.artifacts.assistantContextChannelId ?? channelId;
|
|
12669
|
+
const threadParticipants = buildParticipants(
|
|
12670
|
+
preparedState.conversation.messages
|
|
12671
|
+
);
|
|
12544
12672
|
const reply = await deps.services.generateAssistantReply(userText, {
|
|
12545
12673
|
assistant: {
|
|
12546
12674
|
userName: botConfig.userName
|
|
@@ -12570,6 +12698,7 @@ function createReplyToThread(deps) {
|
|
|
12570
12698
|
sandboxId: preparedState.sandboxId,
|
|
12571
12699
|
sandboxDependencyProfileHash: preparedState.sandboxDependencyProfileHash
|
|
12572
12700
|
},
|
|
12701
|
+
threadParticipants,
|
|
12573
12702
|
onStatus: (status) => progress.setStatus(status),
|
|
12574
12703
|
onTextDelta: (deltaText) => {
|
|
12575
12704
|
if (explicitChannelPostIntent) {
|
|
@@ -12866,6 +12995,7 @@ function createPrepareTurnState(deps) {
|
|
|
12866
12995
|
}
|
|
12867
12996
|
);
|
|
12868
12997
|
const normalizedUserText = normalizeConversationText(args.userText) || "[non-text message]";
|
|
12998
|
+
const slackTs = getSlackMessageTs(args.message);
|
|
12869
12999
|
const incomingUserMessage = {
|
|
12870
13000
|
id: args.message.id,
|
|
12871
13001
|
role: "user",
|
|
@@ -12879,7 +13009,7 @@ function createPrepareTurnState(deps) {
|
|
|
12879
13009
|
},
|
|
12880
13010
|
meta: {
|
|
12881
13011
|
explicitMention: args.explicitMention,
|
|
12882
|
-
slackTs
|
|
13012
|
+
slackTs,
|
|
12883
13013
|
imagesHydrated: !messageHasPotentialImageAttachment
|
|
12884
13014
|
}
|
|
12885
13015
|
};
|
|
@@ -12966,6 +13096,7 @@ function createSlackRuntime(options) {
|
|
|
12966
13096
|
}) => {
|
|
12967
13097
|
const conversation = coerceThreadConversationState(await thread.state);
|
|
12968
13098
|
const normalizedUserText = normalizeConversationText(userText) || "[non-text message]";
|
|
13099
|
+
const slackTs = getSlackMessageTs(message);
|
|
12969
13100
|
upsertConversationMessage(conversation, {
|
|
12970
13101
|
id: message.id,
|
|
12971
13102
|
role: "user",
|
|
@@ -12979,7 +13110,7 @@ function createSlackRuntime(options) {
|
|
|
12979
13110
|
},
|
|
12980
13111
|
meta: {
|
|
12981
13112
|
explicitMention: Boolean(message.isMention),
|
|
12982
|
-
slackTs
|
|
13113
|
+
slackTs,
|
|
12983
13114
|
replied: false,
|
|
12984
13115
|
skippedReason: decision.reason,
|
|
12985
13116
|
imagesHydrated: true
|
|
@@ -13501,9 +13632,121 @@ function getProductionBot() {
|
|
|
13501
13632
|
return productionBot;
|
|
13502
13633
|
}
|
|
13503
13634
|
|
|
13635
|
+
// src/chat/ingress/message-changed.ts
|
|
13636
|
+
import { Message } from "chat";
|
|
13637
|
+
function getEditedMentionMessageId(messageTs) {
|
|
13638
|
+
return `${messageTs}:message_changed_mention`;
|
|
13639
|
+
}
|
|
13640
|
+
function isMessageChangedEnvelope(value) {
|
|
13641
|
+
if (!value || typeof value !== "object") return false;
|
|
13642
|
+
const v = value;
|
|
13643
|
+
if (v.type !== "event_callback") return false;
|
|
13644
|
+
const event = v.event;
|
|
13645
|
+
if (!event || typeof event !== "object") return false;
|
|
13646
|
+
return event.type === "message" && event.subtype === "message_changed" && typeof event.channel === "string" && typeof event.message === "object" && event.message !== null && typeof event.previous_message === "object" && event.previous_message !== null;
|
|
13647
|
+
}
|
|
13648
|
+
function textMentionsBot(text, botUserId) {
|
|
13649
|
+
return text.includes(`<@${botUserId}>`);
|
|
13650
|
+
}
|
|
13651
|
+
function extractMessageChangedMention(body, botUserId, adapter) {
|
|
13652
|
+
if (!isMessageChangedEnvelope(body)) return null;
|
|
13653
|
+
const { event } = body;
|
|
13654
|
+
const newText = event.message.text ?? "";
|
|
13655
|
+
const prevText = event.previous_message.text ?? "";
|
|
13656
|
+
if (!textMentionsBot(newText, botUserId)) return null;
|
|
13657
|
+
if (textMentionsBot(prevText, botUserId)) return null;
|
|
13658
|
+
const channelId = event.channel;
|
|
13659
|
+
const messageTs = event.message.ts;
|
|
13660
|
+
const threadTs = event.message.thread_ts ?? messageTs;
|
|
13661
|
+
const userId = event.message.user ?? "unknown";
|
|
13662
|
+
const threadId = `slack:${channelId}:${threadTs}`;
|
|
13663
|
+
const raw = {
|
|
13664
|
+
channel: channelId,
|
|
13665
|
+
ts: messageTs,
|
|
13666
|
+
thread_ts: threadTs,
|
|
13667
|
+
user: userId
|
|
13668
|
+
};
|
|
13669
|
+
const message = new Message({
|
|
13670
|
+
id: getEditedMentionMessageId(messageTs),
|
|
13671
|
+
threadId,
|
|
13672
|
+
text: newText,
|
|
13673
|
+
isMention: true,
|
|
13674
|
+
attachments: [],
|
|
13675
|
+
metadata: { dateSent: new Date(Number(messageTs) * 1e3), edited: true },
|
|
13676
|
+
formatted: { type: "root", children: [] },
|
|
13677
|
+
raw,
|
|
13678
|
+
author: {
|
|
13679
|
+
userId,
|
|
13680
|
+
userName: userId,
|
|
13681
|
+
fullName: userId,
|
|
13682
|
+
isBot: false,
|
|
13683
|
+
isMe: false
|
|
13684
|
+
}
|
|
13685
|
+
});
|
|
13686
|
+
Object.defineProperty(message, "adapter", {
|
|
13687
|
+
configurable: true,
|
|
13688
|
+
enumerable: false,
|
|
13689
|
+
value: adapter,
|
|
13690
|
+
writable: true
|
|
13691
|
+
});
|
|
13692
|
+
return { threadId, message };
|
|
13693
|
+
}
|
|
13694
|
+
|
|
13504
13695
|
// src/handlers/webhooks.ts
|
|
13505
|
-
|
|
13506
|
-
|
|
13696
|
+
function getSlackPayloadTeamId(body) {
|
|
13697
|
+
if (!body || typeof body !== "object") {
|
|
13698
|
+
return void 0;
|
|
13699
|
+
}
|
|
13700
|
+
const teamId = body.team_id;
|
|
13701
|
+
return typeof teamId === "string" && teamId.length > 0 ? teamId : void 0;
|
|
13702
|
+
}
|
|
13703
|
+
async function handleAuthenticatedSlackMessageChangedMention(args) {
|
|
13704
|
+
const slackAdapter = args.bot.getAdapter("slack");
|
|
13705
|
+
const authAdapter = slackAdapter;
|
|
13706
|
+
const timestamp = args.request.headers.get("x-slack-request-timestamp");
|
|
13707
|
+
const signature = args.request.headers.get("x-slack-signature");
|
|
13708
|
+
if (!authAdapter.verifySignature(args.rawBody, timestamp, signature)) {
|
|
13709
|
+
return;
|
|
13710
|
+
}
|
|
13711
|
+
const webhookOptions = {
|
|
13712
|
+
waitUntil: (task) => args.waitUntil(task)
|
|
13713
|
+
};
|
|
13714
|
+
const dispatch = () => {
|
|
13715
|
+
const botUserId = authAdapter.botUserId;
|
|
13716
|
+
if (!botUserId) {
|
|
13717
|
+
return false;
|
|
13718
|
+
}
|
|
13719
|
+
const result = extractMessageChangedMention(
|
|
13720
|
+
args.body,
|
|
13721
|
+
botUserId,
|
|
13722
|
+
slackAdapter
|
|
13723
|
+
);
|
|
13724
|
+
if (!result) {
|
|
13725
|
+
return false;
|
|
13726
|
+
}
|
|
13727
|
+
args.bot.processMessage(
|
|
13728
|
+
slackAdapter,
|
|
13729
|
+
result.threadId,
|
|
13730
|
+
result.message,
|
|
13731
|
+
webhookOptions
|
|
13732
|
+
);
|
|
13733
|
+
return true;
|
|
13734
|
+
};
|
|
13735
|
+
if (authAdapter.defaultBotToken) {
|
|
13736
|
+
dispatch();
|
|
13737
|
+
return;
|
|
13738
|
+
}
|
|
13739
|
+
const teamId = getSlackPayloadTeamId(args.body);
|
|
13740
|
+
if (!teamId || !authAdapter.resolveTokenForTeam || !authAdapter.requestContext) {
|
|
13741
|
+
return;
|
|
13742
|
+
}
|
|
13743
|
+
const context = await authAdapter.resolveTokenForTeam(teamId);
|
|
13744
|
+
if (!context) {
|
|
13745
|
+
return;
|
|
13746
|
+
}
|
|
13747
|
+
authAdapter.requestContext.run(context, dispatch);
|
|
13748
|
+
}
|
|
13749
|
+
async function handlePlatformWebhook(request, platform, waitUntil, bot = getProductionBot()) {
|
|
13507
13750
|
const handler = bot.webhooks[platform];
|
|
13508
13751
|
const requestContext = createRequestContext(request, { platform });
|
|
13509
13752
|
const requestUrl = new URL(request.url);
|
|
@@ -13521,6 +13764,34 @@ async function POST(request, platform, waitUntil) {
|
|
|
13521
13764
|
);
|
|
13522
13765
|
return new Response(`Unknown platform: ${platform}`, { status: 404 });
|
|
13523
13766
|
}
|
|
13767
|
+
let rebuiltRequest = request;
|
|
13768
|
+
if (platform === "slack") {
|
|
13769
|
+
const rawBody = await request.text();
|
|
13770
|
+
let parsedBody;
|
|
13771
|
+
try {
|
|
13772
|
+
parsedBody = JSON.parse(rawBody);
|
|
13773
|
+
} catch {
|
|
13774
|
+
parsedBody = void 0;
|
|
13775
|
+
}
|
|
13776
|
+
if (parsedBody && isMessageChangedEnvelope(parsedBody)) {
|
|
13777
|
+
try {
|
|
13778
|
+
await handleAuthenticatedSlackMessageChangedMention({
|
|
13779
|
+
body: parsedBody,
|
|
13780
|
+
bot,
|
|
13781
|
+
rawBody,
|
|
13782
|
+
request,
|
|
13783
|
+
waitUntil
|
|
13784
|
+
});
|
|
13785
|
+
} catch (error) {
|
|
13786
|
+
logException(error, "slack_message_changed_side_channel_failed");
|
|
13787
|
+
}
|
|
13788
|
+
}
|
|
13789
|
+
rebuiltRequest = new Request(request.url, {
|
|
13790
|
+
method: request.method,
|
|
13791
|
+
headers: request.headers,
|
|
13792
|
+
body: rawBody
|
|
13793
|
+
});
|
|
13794
|
+
}
|
|
13524
13795
|
try {
|
|
13525
13796
|
return await withSpan(
|
|
13526
13797
|
"http.server.request",
|
|
@@ -13528,7 +13799,7 @@ async function POST(request, platform, waitUntil) {
|
|
|
13528
13799
|
requestContext,
|
|
13529
13800
|
async () => {
|
|
13530
13801
|
try {
|
|
13531
|
-
const response = await handler(
|
|
13802
|
+
const response = await handler(rebuiltRequest, {
|
|
13532
13803
|
waitUntil: (task) => waitUntil(task)
|
|
13533
13804
|
});
|
|
13534
13805
|
if (response.status >= 400) {
|
|
@@ -13574,6 +13845,9 @@ async function POST(request, platform, waitUntil) {
|
|
|
13574
13845
|
}
|
|
13575
13846
|
});
|
|
13576
13847
|
}
|
|
13848
|
+
async function POST(request, platform, waitUntil) {
|
|
13849
|
+
return handlePlatformWebhook(request, platform, waitUntil);
|
|
13850
|
+
}
|
|
13577
13851
|
|
|
13578
13852
|
// src/app.ts
|
|
13579
13853
|
async function defaultWaitUntil() {
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
import {
|
|
5
5
|
discoverInstalledPluginPackageContent,
|
|
6
6
|
pluginRoots
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-XPXD3FCE.js";
|
|
8
8
|
|
|
9
9
|
// src/chat/logging.ts
|
|
10
10
|
import { AsyncLocalStorage } from "async_hooks";
|
|
@@ -1738,6 +1738,29 @@ var CredentialUnavailableError = class extends Error {
|
|
|
1738
1738
|
}
|
|
1739
1739
|
};
|
|
1740
1740
|
|
|
1741
|
+
// src/chat/credentials/oauth-scope.ts
|
|
1742
|
+
function parseScope(scope) {
|
|
1743
|
+
if (!scope) {
|
|
1744
|
+
return [];
|
|
1745
|
+
}
|
|
1746
|
+
return [...new Set(scope.split(/\s+/).filter(Boolean))].sort();
|
|
1747
|
+
}
|
|
1748
|
+
function normalizeOAuthScope(scope) {
|
|
1749
|
+
const parsed = parseScope(scope);
|
|
1750
|
+
return parsed.length > 0 ? parsed.join(" ") : void 0;
|
|
1751
|
+
}
|
|
1752
|
+
function hasRequiredOAuthScope(storedScope, requiredScope) {
|
|
1753
|
+
const required = parseScope(requiredScope);
|
|
1754
|
+
if (required.length === 0) {
|
|
1755
|
+
return true;
|
|
1756
|
+
}
|
|
1757
|
+
const stored = new Set(parseScope(storedScope));
|
|
1758
|
+
if (stored.size === 0) {
|
|
1759
|
+
return false;
|
|
1760
|
+
}
|
|
1761
|
+
return required.every((scope) => stored.has(scope));
|
|
1762
|
+
}
|
|
1763
|
+
|
|
1741
1764
|
// src/chat/plugins/auth/oauth-request.ts
|
|
1742
1765
|
var DEFAULT_TOKEN_CONTENT_TYPE = "application/x-www-form-urlencoded";
|
|
1743
1766
|
function requireNonEmptyTokenField(data, field) {
|
|
@@ -1785,12 +1808,22 @@ function buildOAuthTokenRequest(input) {
|
|
|
1785
1808
|
body: contentTypeToBody(contentType, payload)
|
|
1786
1809
|
};
|
|
1787
1810
|
}
|
|
1788
|
-
function parseOAuthTokenResponse(data) {
|
|
1811
|
+
function parseOAuthTokenResponse(data, fallbackScope) {
|
|
1789
1812
|
const accessToken = requireNonEmptyTokenField(data, "access_token");
|
|
1790
1813
|
const refreshToken = requireNonEmptyTokenField(data, "refresh_token");
|
|
1791
1814
|
const expiresIn = data.expires_in;
|
|
1815
|
+
const responseScope = data.scope;
|
|
1816
|
+
let scope;
|
|
1817
|
+
if (responseScope !== void 0) {
|
|
1818
|
+
if (typeof responseScope !== "string" || !responseScope.trim()) {
|
|
1819
|
+
throw new Error("OAuth token response returned invalid scope");
|
|
1820
|
+
}
|
|
1821
|
+
scope = normalizeOAuthScope(responseScope);
|
|
1822
|
+
} else {
|
|
1823
|
+
scope = normalizeOAuthScope(fallbackScope);
|
|
1824
|
+
}
|
|
1792
1825
|
if (expiresIn === void 0) {
|
|
1793
|
-
return { accessToken, refreshToken };
|
|
1826
|
+
return { accessToken, refreshToken, ...scope ? { scope } : {} };
|
|
1794
1827
|
}
|
|
1795
1828
|
if (typeof expiresIn !== "number" || !Number.isFinite(expiresIn) || expiresIn <= 0) {
|
|
1796
1829
|
throw new Error("OAuth token response returned invalid expires_in");
|
|
@@ -1798,14 +1831,15 @@ function parseOAuthTokenResponse(data) {
|
|
|
1798
1831
|
return {
|
|
1799
1832
|
accessToken,
|
|
1800
1833
|
refreshToken,
|
|
1801
|
-
expiresAt: Date.now() + expiresIn * 1e3
|
|
1834
|
+
expiresAt: Date.now() + expiresIn * 1e3,
|
|
1835
|
+
...scope ? { scope } : {}
|
|
1802
1836
|
};
|
|
1803
1837
|
}
|
|
1804
1838
|
|
|
1805
1839
|
// src/chat/plugins/auth/oauth-bearer-broker.ts
|
|
1806
1840
|
var MAX_LEASE_MS2 = 60 * 60 * 1e3;
|
|
1807
1841
|
var REFRESH_BUFFER_MS = 5 * 60 * 1e3;
|
|
1808
|
-
async function refreshAccessToken(refreshToken, oauth) {
|
|
1842
|
+
async function refreshAccessToken(refreshToken, oauth, fallbackScope) {
|
|
1809
1843
|
const clientId = process.env[oauth.clientIdEnv]?.trim();
|
|
1810
1844
|
const clientSecret = process.env[oauth.clientSecretEnv]?.trim();
|
|
1811
1845
|
if (!clientId || !clientSecret) {
|
|
@@ -1832,7 +1866,7 @@ async function refreshAccessToken(refreshToken, oauth) {
|
|
|
1832
1866
|
throw new Error(`Token refresh failed: ${response.status}`);
|
|
1833
1867
|
}
|
|
1834
1868
|
const data = await response.json();
|
|
1835
|
-
return parseOAuthTokenResponse(data);
|
|
1869
|
+
return parseOAuthTokenResponse(data, fallbackScope);
|
|
1836
1870
|
}
|
|
1837
1871
|
function getLeaseExpiry(expiresAt) {
|
|
1838
1872
|
return expiresAt ? Math.min(expiresAt, Date.now() + MAX_LEASE_MS2) : Date.now() + MAX_LEASE_MS2;
|
|
@@ -1885,13 +1919,26 @@ function createOAuthBearerBroker(manifest, credentials, deps) {
|
|
|
1885
1919
|
provider
|
|
1886
1920
|
);
|
|
1887
1921
|
if (stored) {
|
|
1922
|
+
if (!hasRequiredOAuthScope(stored.scope, oauth.scope)) {
|
|
1923
|
+
throw new CredentialUnavailableError(
|
|
1924
|
+
provider,
|
|
1925
|
+
`Your ${provider} connection needs to be reauthorized.`
|
|
1926
|
+
);
|
|
1927
|
+
}
|
|
1888
1928
|
const now = Date.now();
|
|
1889
1929
|
if (stored.expiresAt !== void 0 && stored.expiresAt - now < REFRESH_BUFFER_MS) {
|
|
1890
1930
|
try {
|
|
1891
1931
|
const refreshed = await refreshAccessToken(
|
|
1892
1932
|
stored.refreshToken,
|
|
1893
|
-
oauth
|
|
1933
|
+
oauth,
|
|
1934
|
+
stored.scope ?? oauth.scope
|
|
1894
1935
|
);
|
|
1936
|
+
if (!hasRequiredOAuthScope(refreshed.scope, oauth.scope)) {
|
|
1937
|
+
throw new CredentialUnavailableError(
|
|
1938
|
+
provider,
|
|
1939
|
+
`Your ${provider} connection needs to be reauthorized.`
|
|
1940
|
+
);
|
|
1941
|
+
}
|
|
1895
1942
|
await deps.userTokenStore.set(
|
|
1896
1943
|
input.requesterId,
|
|
1897
1944
|
provider,
|
|
@@ -1903,7 +1950,10 @@ function createOAuthBearerBroker(manifest, credentials, deps) {
|
|
|
1903
1950
|
getLeaseExpiry(refreshed.expiresAt),
|
|
1904
1951
|
input.reason
|
|
1905
1952
|
);
|
|
1906
|
-
} catch {
|
|
1953
|
+
} catch (error) {
|
|
1954
|
+
if (error instanceof CredentialUnavailableError) {
|
|
1955
|
+
throw error;
|
|
1956
|
+
}
|
|
1907
1957
|
if (stored.expiresAt > Date.now()) {
|
|
1908
1958
|
return buildLease(
|
|
1909
1959
|
stored.accessToken,
|
|
@@ -2303,6 +2353,7 @@ export {
|
|
|
2303
2353
|
resolveAuthTokenPlaceholder,
|
|
2304
2354
|
parsePluginManifest,
|
|
2305
2355
|
CredentialUnavailableError,
|
|
2356
|
+
hasRequiredOAuthScope,
|
|
2306
2357
|
buildOAuthTokenRequest,
|
|
2307
2358
|
parseOAuthTokenResponse,
|
|
2308
2359
|
getPluginCatalogSignature,
|
|
@@ -5,10 +5,10 @@ import {
|
|
|
5
5
|
getPluginSkillRoots,
|
|
6
6
|
logInfo,
|
|
7
7
|
logWarn
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-N4ICA2BC.js";
|
|
9
9
|
import {
|
|
10
10
|
skillRoots
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-XPXD3FCE.js";
|
|
12
12
|
|
|
13
13
|
// src/chat/skills.ts
|
|
14
14
|
import fs from "fs/promises";
|
|
@@ -113,14 +113,14 @@ function pathExists(targetPath) {
|
|
|
113
113
|
}
|
|
114
114
|
}
|
|
115
115
|
function hasAnyDataMarkers(appDir) {
|
|
116
|
-
return pathExists(path.join(appDir, "SOUL.md")) || pathExists(path.join(appDir, "
|
|
116
|
+
return pathExists(path.join(appDir, "SOUL.md")) || pathExists(path.join(appDir, "WORLD.md"));
|
|
117
117
|
}
|
|
118
118
|
function scoreAppCandidate(appDir) {
|
|
119
119
|
let score = 0;
|
|
120
120
|
if (pathExists(path.join(appDir, "SOUL.md"))) {
|
|
121
121
|
score += 4;
|
|
122
122
|
}
|
|
123
|
-
if (pathExists(path.join(appDir, "
|
|
123
|
+
if (pathExists(path.join(appDir, "WORLD.md"))) {
|
|
124
124
|
score += 2;
|
|
125
125
|
}
|
|
126
126
|
if (pathExists(path.join(appDir, "skills"))) {
|
|
@@ -198,10 +198,27 @@ function soulPathCandidates() {
|
|
|
198
198
|
const candidates = dataRoots().map((root) => path.join(root, "SOUL.md"));
|
|
199
199
|
return unique(candidates);
|
|
200
200
|
}
|
|
201
|
-
function
|
|
202
|
-
const candidates = dataRoots().map((root) => path.join(root, "
|
|
201
|
+
function worldPathCandidates() {
|
|
202
|
+
const candidates = dataRoots().map((root) => path.join(root, "WORLD.md"));
|
|
203
203
|
return unique(candidates);
|
|
204
204
|
}
|
|
205
|
+
var RESERVED_APP_FILES = /* @__PURE__ */ new Set([
|
|
206
|
+
"SOUL.md",
|
|
207
|
+
"WORLD.md",
|
|
208
|
+
"DESCRIPTION.md",
|
|
209
|
+
"ABOUT.md"
|
|
210
|
+
]);
|
|
211
|
+
function listReferenceFiles() {
|
|
212
|
+
const appDir = homeDir();
|
|
213
|
+
try {
|
|
214
|
+
const entries = fs.readdirSync(appDir, { withFileTypes: true });
|
|
215
|
+
return entries.filter(
|
|
216
|
+
(entry) => entry.isFile() && entry.name.endsWith(".md") && !RESERVED_APP_FILES.has(entry.name)
|
|
217
|
+
).map((entry) => path.join(appDir, entry.name)).sort();
|
|
218
|
+
} catch {
|
|
219
|
+
return [];
|
|
220
|
+
}
|
|
221
|
+
}
|
|
205
222
|
|
|
206
223
|
// src/chat/plugins/package-discovery.ts
|
|
207
224
|
function normalizeForGlob(targetPath) {
|
|
@@ -336,7 +353,8 @@ export {
|
|
|
336
353
|
skillRoots,
|
|
337
354
|
pluginRoots,
|
|
338
355
|
soulPathCandidates,
|
|
339
|
-
|
|
356
|
+
worldPathCandidates,
|
|
357
|
+
listReferenceFiles,
|
|
340
358
|
setPluginPackages,
|
|
341
359
|
discoverInstalledPluginPackageContent
|
|
342
360
|
};
|
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
getPluginRuntimeDependencies,
|
|
3
3
|
getPluginRuntimePostinstall,
|
|
4
4
|
withSpan
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-N4ICA2BC.js";
|
|
6
6
|
|
|
7
7
|
// src/chat/state/adapter.ts
|
|
8
8
|
import { createMemoryState } from "@chat-adapter/state-memory";
|
|
@@ -252,8 +252,11 @@ function normalizeWorkspaceRoot(input) {
|
|
|
252
252
|
const normalized = candidate.replace(/\/+$/, "");
|
|
253
253
|
return normalized.startsWith("/") ? normalized : `/${normalized}`;
|
|
254
254
|
}
|
|
255
|
-
var SANDBOX_WORKSPACE_ROOT = normalizeWorkspaceRoot(
|
|
255
|
+
var SANDBOX_WORKSPACE_ROOT = normalizeWorkspaceRoot(
|
|
256
|
+
process.env.VERCEL_SANDBOX_WORKSPACE_DIR
|
|
257
|
+
);
|
|
256
258
|
var SANDBOX_SKILLS_ROOT = `${SANDBOX_WORKSPACE_ROOT}/skills`;
|
|
259
|
+
var SANDBOX_DATA_ROOT = `${SANDBOX_WORKSPACE_ROOT}/data`;
|
|
257
260
|
function sandboxSkillDir(skillName) {
|
|
258
261
|
return `${SANDBOX_SKILLS_ROOT}/${skillName}`;
|
|
259
262
|
}
|
|
@@ -814,6 +817,7 @@ export {
|
|
|
814
817
|
disconnectStateAdapter,
|
|
815
818
|
SANDBOX_WORKSPACE_ROOT,
|
|
816
819
|
SANDBOX_SKILLS_ROOT,
|
|
820
|
+
SANDBOX_DATA_ROOT,
|
|
817
821
|
sandboxSkillDir,
|
|
818
822
|
sandboxSkillFile,
|
|
819
823
|
buildNonInteractiveShellScript,
|
package/dist/cli/check.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
parseSkillFile
|
|
3
|
-
} from "../chunk-
|
|
3
|
+
} from "../chunk-NRSP2MLC.js";
|
|
4
4
|
import {
|
|
5
5
|
parsePluginManifest
|
|
6
|
-
} from "../chunk-
|
|
6
|
+
} from "../chunk-N4ICA2BC.js";
|
|
7
7
|
import "../chunk-Z3YD6NHK.js";
|
|
8
|
-
import "../chunk-
|
|
8
|
+
import "../chunk-XPXD3FCE.js";
|
|
9
9
|
import "../chunk-2KG3PWR4.js";
|
|
10
10
|
|
|
11
11
|
// src/cli/check.ts
|
|
@@ -223,6 +223,45 @@ function reportAppSkills(skillResults, io) {
|
|
|
223
223
|
reportSkillResult(skillResult, io, " ", index === skillResults.length - 1);
|
|
224
224
|
}
|
|
225
225
|
}
|
|
226
|
+
async function validateAppFiles(appDir) {
|
|
227
|
+
const errors = [];
|
|
228
|
+
const warnings = [];
|
|
229
|
+
if (await pathIsFile(path.join(appDir, "ABOUT.md"))) {
|
|
230
|
+
errors.push(
|
|
231
|
+
`${path.join(appDir, "ABOUT.md")}: ABOUT.md is no longer supported. Rename to WORLD.md (operational context) and DESCRIPTION.md (user-facing description).`
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
if (!await pathIsFile(path.join(appDir, "SOUL.md"))) {
|
|
235
|
+
warnings.push(`${path.join(appDir, "SOUL.md")}: missing SOUL.md`);
|
|
236
|
+
}
|
|
237
|
+
if (!await pathIsFile(path.join(appDir, "WORLD.md"))) {
|
|
238
|
+
warnings.push(`${path.join(appDir, "WORLD.md")}: missing WORLD.md`);
|
|
239
|
+
}
|
|
240
|
+
if (!await pathIsFile(path.join(appDir, "DESCRIPTION.md"))) {
|
|
241
|
+
warnings.push(
|
|
242
|
+
`${path.join(appDir, "DESCRIPTION.md")}: missing DESCRIPTION.md`
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
return { errors, warnings };
|
|
246
|
+
}
|
|
247
|
+
async function hasJuniorAppMarkers(appDir) {
|
|
248
|
+
for (const fileName of [
|
|
249
|
+
"SOUL.md",
|
|
250
|
+
"WORLD.md",
|
|
251
|
+
"DESCRIPTION.md",
|
|
252
|
+
"ABOUT.md"
|
|
253
|
+
]) {
|
|
254
|
+
if (await pathIsFile(path.join(appDir, fileName))) {
|
|
255
|
+
return true;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
for (const dirName of ["skills", "plugins"]) {
|
|
259
|
+
if (await pathIsDirectory(path.join(appDir, dirName))) {
|
|
260
|
+
return true;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
return false;
|
|
264
|
+
}
|
|
226
265
|
async function runCheck(rootDir = process.cwd(), io = DEFAULT_IO) {
|
|
227
266
|
const resolvedRoot = path.resolve(rootDir);
|
|
228
267
|
if (!await pathIsDirectory(resolvedRoot)) {
|
|
@@ -274,12 +313,30 @@ async function runCheck(rootDir = process.cwd(), io = DEFAULT_IO) {
|
|
|
274
313
|
pluginResult.skillResults = (pluginSkillDirs.get(pluginResult.pluginDir) ?? []).map((skillDir) => skillResultsByDir.get(skillDir)).filter((result) => Boolean(result));
|
|
275
314
|
}
|
|
276
315
|
const appSkillResults = appSkillDirs.map((skillDir) => skillResultsByDir.get(skillDir)).filter((result) => Boolean(result));
|
|
316
|
+
const appDir = path.resolve(resolvedRoot, "app");
|
|
317
|
+
let appFileResult = {
|
|
318
|
+
errors: [],
|
|
319
|
+
warnings: []
|
|
320
|
+
};
|
|
321
|
+
const shouldValidateAppFiles = await pathIsDirectory(appDir) && await hasJuniorAppMarkers(appDir);
|
|
322
|
+
if (shouldValidateAppFiles) {
|
|
323
|
+
appFileResult = await validateAppFiles(appDir);
|
|
324
|
+
warnings.push(...appFileResult.warnings);
|
|
325
|
+
errors.push(...appFileResult.errors);
|
|
326
|
+
}
|
|
277
327
|
io.info(
|
|
278
328
|
`${color("Checking", ANSI.bold, ANSI.cyan)} ${color(
|
|
279
329
|
formatDisplayPath(resolvedRoot, resolvedRoot),
|
|
280
330
|
ANSI.dim
|
|
281
331
|
)}`
|
|
282
332
|
);
|
|
333
|
+
if (shouldValidateAppFiles) {
|
|
334
|
+
const appFileStatus = formatStatus(
|
|
335
|
+
appFileResult.errors.length,
|
|
336
|
+
appFileResult.warnings.length
|
|
337
|
+
);
|
|
338
|
+
io.info(formatHeading(appFileStatus, "app files"));
|
|
339
|
+
}
|
|
283
340
|
for (const pluginResult of pluginResults) {
|
|
284
341
|
reportPluginResult(pluginResult, io);
|
|
285
342
|
}
|
package/dist/cli/init.js
CHANGED
|
@@ -109,10 +109,15 @@ You are ${name}, a helpful assistant.
|
|
|
109
109
|
`
|
|
110
110
|
);
|
|
111
111
|
fs.writeFileSync(
|
|
112
|
-
path.join(appDir, "
|
|
113
|
-
`#
|
|
112
|
+
path.join(appDir, "WORLD.md"),
|
|
113
|
+
`# ${name} World
|
|
114
114
|
|
|
115
|
-
|
|
115
|
+
Operational context and domain knowledge for ${name}.
|
|
116
|
+
`
|
|
117
|
+
);
|
|
118
|
+
fs.writeFileSync(
|
|
119
|
+
path.join(appDir, "DESCRIPTION.md"),
|
|
120
|
+
`${name} helps your team make progress directly in Slack.
|
|
116
121
|
`
|
|
117
122
|
);
|
|
118
123
|
const skillsDir = path.join(appDir, "skills");
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
2
|
disconnectStateAdapter,
|
|
3
3
|
resolveRuntimeDependencySnapshot
|
|
4
|
-
} from "../chunk-
|
|
4
|
+
} from "../chunk-Z43DS7XN.js";
|
|
5
5
|
import {
|
|
6
6
|
getPluginProviders,
|
|
7
7
|
getPluginRuntimeDependencies,
|
|
8
8
|
getPluginRuntimePostinstall
|
|
9
|
-
} from "../chunk-
|
|
9
|
+
} from "../chunk-N4ICA2BC.js";
|
|
10
10
|
import "../chunk-Z3YD6NHK.js";
|
|
11
|
-
import "../chunk-
|
|
11
|
+
import "../chunk-XPXD3FCE.js";
|
|
12
12
|
import "../chunk-2KG3PWR4.js";
|
|
13
13
|
|
|
14
14
|
// src/cli/snapshot-warmup.ts
|
package/dist/nitro.js
CHANGED