@openchamber/web 1.4.2 → 1.4.4
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/bin/cli.js +44 -9
- package/dist/assets/{ToolOutputDialog-zILn8Ed6.js → ToolOutputDialog-BXPi0SDL.js} +3 -3
- package/dist/assets/{index-5Ree9Z_i.js → index-CqQbtUxU.js} +2 -2
- package/dist/assets/index-DR2OFuzB.css +1 -0
- package/dist/assets/main-j7ViaNnX.js +127 -0
- package/dist/assets/{vendor-.bun-COPXsM7o.js → vendor-.bun-BEzqubWg.js} +418 -414
- package/dist/index.html +3 -3
- package/package.json +3 -2
- package/server/index.js +880 -90
- package/server/lib/git-service.js +30 -1
- package/server/lib/opencode-config.js +306 -29
- package/dist/assets/index-msMCcGYO.css +0 -1
- package/dist/assets/main-DF2J5RAs.js +0 -122
|
@@ -29,6 +29,22 @@ const normalizeDirectoryPath = (value) => {
|
|
|
29
29
|
return trimmed;
|
|
30
30
|
};
|
|
31
31
|
|
|
32
|
+
const cleanBranchName = (branch) => {
|
|
33
|
+
if (!branch) {
|
|
34
|
+
return branch;
|
|
35
|
+
}
|
|
36
|
+
if (branch.startsWith('refs/heads/')) {
|
|
37
|
+
return branch.substring('refs/heads/'.length);
|
|
38
|
+
}
|
|
39
|
+
if (branch.startsWith('heads/')) {
|
|
40
|
+
return branch.substring('heads/'.length);
|
|
41
|
+
}
|
|
42
|
+
if (branch.startsWith('refs/')) {
|
|
43
|
+
return branch.substring('refs/'.length);
|
|
44
|
+
}
|
|
45
|
+
return branch;
|
|
46
|
+
};
|
|
47
|
+
|
|
32
48
|
export async function isGitRepository(directory) {
|
|
33
49
|
const directoryPath = normalizeDirectoryPath(directory);
|
|
34
50
|
if (!directoryPath || !fs.existsSync(directoryPath)) {
|
|
@@ -805,7 +821,7 @@ export async function getWorktrees(directory) {
|
|
|
805
821
|
} else if (line.startsWith('HEAD ')) {
|
|
806
822
|
current.head = line.substring(5);
|
|
807
823
|
} else if (line.startsWith('branch ')) {
|
|
808
|
-
current.branch = line.substring(7);
|
|
824
|
+
current.branch = cleanBranchName(line.substring(7));
|
|
809
825
|
} else if (line === '') {
|
|
810
826
|
if (current.worktree) {
|
|
811
827
|
worktrees.push(current);
|
|
@@ -1086,3 +1102,16 @@ export async function getCommitFiles(directory, commitHash) {
|
|
|
1086
1102
|
throw error;
|
|
1087
1103
|
}
|
|
1088
1104
|
}
|
|
1105
|
+
|
|
1106
|
+
export async function renameBranch(directory, oldName, newName) {
|
|
1107
|
+
const git = simpleGit(normalizeDirectoryPath(directory));
|
|
1108
|
+
|
|
1109
|
+
try {
|
|
1110
|
+
// Use git branch -m command to rename the branch
|
|
1111
|
+
await git.raw(['branch', '-m', oldName, newName]);
|
|
1112
|
+
return { success: true, branch: newName };
|
|
1113
|
+
} catch (error) {
|
|
1114
|
+
console.error('Failed to rename branch:', error);
|
|
1115
|
+
throw error;
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
@@ -101,22 +101,72 @@ function getAgentWritePath(agentName, workingDirectory, requestedScope) {
|
|
|
101
101
|
if (existing.path) {
|
|
102
102
|
return existing;
|
|
103
103
|
}
|
|
104
|
-
|
|
104
|
+
|
|
105
105
|
// For new agents or built-in overrides: use requested scope or default to user
|
|
106
106
|
const scope = requestedScope || AGENT_SCOPE.USER;
|
|
107
107
|
if (scope === AGENT_SCOPE.PROJECT && workingDirectory) {
|
|
108
|
-
return {
|
|
109
|
-
scope: AGENT_SCOPE.PROJECT,
|
|
110
|
-
path: getProjectAgentPath(workingDirectory, agentName)
|
|
108
|
+
return {
|
|
109
|
+
scope: AGENT_SCOPE.PROJECT,
|
|
110
|
+
path: getProjectAgentPath(workingDirectory, agentName)
|
|
111
111
|
};
|
|
112
112
|
}
|
|
113
|
-
|
|
114
|
-
return {
|
|
115
|
-
scope: AGENT_SCOPE.USER,
|
|
116
|
-
path: getUserAgentPath(agentName)
|
|
113
|
+
|
|
114
|
+
return {
|
|
115
|
+
scope: AGENT_SCOPE.USER,
|
|
116
|
+
path: getUserAgentPath(agentName)
|
|
117
117
|
};
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
+
/**
|
|
121
|
+
* Detect where an agent's permission field is currently defined
|
|
122
|
+
* Priority: project .md > user .md > project JSON > user JSON
|
|
123
|
+
* Returns: { source: 'md'|'json'|null, scope: 'project'|'user'|null, path: string|null }
|
|
124
|
+
*/
|
|
125
|
+
function getAgentPermissionSource(agentName, workingDirectory) {
|
|
126
|
+
// Check project-level .md first
|
|
127
|
+
if (workingDirectory) {
|
|
128
|
+
const projectMdPath = getProjectAgentPath(workingDirectory, agentName);
|
|
129
|
+
if (fs.existsSync(projectMdPath)) {
|
|
130
|
+
const { frontmatter } = parseMdFile(projectMdPath);
|
|
131
|
+
if (frontmatter.permission !== undefined) {
|
|
132
|
+
return { source: 'md', scope: AGENT_SCOPE.PROJECT, path: projectMdPath };
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Check user-level .md
|
|
138
|
+
const userMdPath = getUserAgentPath(agentName);
|
|
139
|
+
if (fs.existsSync(userMdPath)) {
|
|
140
|
+
const { frontmatter } = parseMdFile(userMdPath);
|
|
141
|
+
if (frontmatter.permission !== undefined) {
|
|
142
|
+
return { source: 'md', scope: AGENT_SCOPE.USER, path: userMdPath };
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Check JSON layers (project > user)
|
|
147
|
+
const layers = readConfigLayers(workingDirectory);
|
|
148
|
+
|
|
149
|
+
// Project opencode.json
|
|
150
|
+
const projectJsonPermission = layers.projectConfig?.agent?.[agentName]?.permission;
|
|
151
|
+
if (projectJsonPermission !== undefined && layers.paths.projectPath) {
|
|
152
|
+
return { source: 'json', scope: AGENT_SCOPE.PROJECT, path: layers.paths.projectPath };
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// User opencode.json
|
|
156
|
+
const userJsonPermission = layers.userConfig?.agent?.[agentName]?.permission;
|
|
157
|
+
if (userJsonPermission !== undefined) {
|
|
158
|
+
return { source: 'json', scope: AGENT_SCOPE.USER, path: layers.paths.userPath };
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Custom config (env var)
|
|
162
|
+
const customJsonPermission = layers.customConfig?.agent?.[agentName]?.permission;
|
|
163
|
+
if (customJsonPermission !== undefined && layers.paths.customPath) {
|
|
164
|
+
return { source: 'json', scope: 'custom', path: layers.paths.customPath };
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return { source: null, scope: null, path: null };
|
|
168
|
+
}
|
|
169
|
+
|
|
120
170
|
// ============== COMMAND SCOPE HELPERS ==============
|
|
121
171
|
|
|
122
172
|
/**
|
|
@@ -412,9 +462,125 @@ function writePromptFile(filePath, content) {
|
|
|
412
462
|
console.log(`Updated prompt file: ${filePath}`);
|
|
413
463
|
}
|
|
414
464
|
|
|
465
|
+
/**
|
|
466
|
+
* Get all possible project config paths in priority order
|
|
467
|
+
* Priority: root > .opencode/, json > jsonc
|
|
468
|
+
*/
|
|
469
|
+
function getProjectConfigCandidates(workingDirectory) {
|
|
470
|
+
if (!workingDirectory) return [];
|
|
471
|
+
return [
|
|
472
|
+
path.join(workingDirectory, 'opencode.json'),
|
|
473
|
+
path.join(workingDirectory, 'opencode.jsonc'),
|
|
474
|
+
path.join(workingDirectory, '.opencode', 'opencode.json'),
|
|
475
|
+
path.join(workingDirectory, '.opencode', 'opencode.jsonc'),
|
|
476
|
+
];
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
/**
|
|
480
|
+
* Find existing project config file or return default path for new config
|
|
481
|
+
*/
|
|
415
482
|
function getProjectConfigPath(workingDirectory) {
|
|
416
483
|
if (!workingDirectory) return null;
|
|
417
|
-
|
|
484
|
+
|
|
485
|
+
const candidates = getProjectConfigCandidates(workingDirectory);
|
|
486
|
+
|
|
487
|
+
// Return first existing config file
|
|
488
|
+
for (const candidate of candidates) {
|
|
489
|
+
if (fs.existsSync(candidate)) {
|
|
490
|
+
return candidate;
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
// Default to root opencode.json for new configs
|
|
495
|
+
return candidates[0];
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
/**
|
|
499
|
+
* Merge new permission config with existing non-wildcard patterns
|
|
500
|
+
* Non-wildcard patterns (patterns other than "*") are preserved from existing config
|
|
501
|
+
* @param {object|string|null} newPermission - New permission config from UI (wildcards only)
|
|
502
|
+
* @param {object} permissionSource - Result from getAgentPermissionSource
|
|
503
|
+
* @param {string} agentName - Agent name
|
|
504
|
+
* @param {string|null} workingDirectory - Working directory
|
|
505
|
+
* @returns {object|string|null} Merged permission config
|
|
506
|
+
*/
|
|
507
|
+
function mergePermissionWithNonWildcards(newPermission, permissionSource, agentName, workingDirectory) {
|
|
508
|
+
// If no existing permission, return new permission as-is
|
|
509
|
+
if (!permissionSource.source || !permissionSource.path) {
|
|
510
|
+
return newPermission;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
// Get existing permission config
|
|
514
|
+
let existingPermission = null;
|
|
515
|
+
if (permissionSource.source === 'md') {
|
|
516
|
+
const { frontmatter } = parseMdFile(permissionSource.path);
|
|
517
|
+
existingPermission = frontmatter.permission;
|
|
518
|
+
} else if (permissionSource.source === 'json') {
|
|
519
|
+
const config = readConfigFile(permissionSource.path);
|
|
520
|
+
existingPermission = config?.agent?.[agentName]?.permission;
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
// If no existing permission or it's a simple string, return new permission as-is
|
|
524
|
+
if (!existingPermission || typeof existingPermission === 'string') {
|
|
525
|
+
return newPermission;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
// If new permission is null/undefined, return null to clear it
|
|
529
|
+
if (newPermission == null) {
|
|
530
|
+
return null;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
// If new permission is a simple string (e.g., "allow"), return it as-is
|
|
534
|
+
if (typeof newPermission === 'string') {
|
|
535
|
+
return newPermission;
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
// Extract non-wildcard patterns from existing permission
|
|
539
|
+
const nonWildcardPatterns = {};
|
|
540
|
+
for (const [permKey, permValue] of Object.entries(existingPermission)) {
|
|
541
|
+
if (permKey === '*') continue; // Skip global default
|
|
542
|
+
|
|
543
|
+
if (typeof permValue === 'object' && permValue !== null && !Array.isArray(permValue)) {
|
|
544
|
+
// Permission has pattern-based config (e.g., { "npm *": "allow", "*": "ask" })
|
|
545
|
+
const nonWildcards = {};
|
|
546
|
+
for (const [pattern, action] of Object.entries(permValue)) {
|
|
547
|
+
if (pattern !== '*') {
|
|
548
|
+
nonWildcards[pattern] = action;
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
if (Object.keys(nonWildcards).length > 0) {
|
|
552
|
+
nonWildcardPatterns[permKey] = nonWildcards;
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
// Simple string values (e.g., "allow") don't have patterns, skip them
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
// If no non-wildcard patterns to preserve, return new permission as-is
|
|
559
|
+
if (Object.keys(nonWildcardPatterns).length === 0) {
|
|
560
|
+
return newPermission;
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
// Merge non-wildcards into new permission
|
|
564
|
+
const merged = { ...newPermission };
|
|
565
|
+
for (const [permKey, patterns] of Object.entries(nonWildcardPatterns)) {
|
|
566
|
+
const newValue = merged[permKey];
|
|
567
|
+
if (typeof newValue === 'string') {
|
|
568
|
+
// Convert string to object with wildcard + preserved patterns
|
|
569
|
+
merged[permKey] = { '*': newValue, ...patterns };
|
|
570
|
+
} else if (typeof newValue === 'object' && newValue !== null) {
|
|
571
|
+
// Merge patterns, new wildcards take precedence
|
|
572
|
+
merged[permKey] = { ...patterns, ...newValue };
|
|
573
|
+
} else {
|
|
574
|
+
// Permission not in new config - preserve existing patterns with their wildcard if it existed
|
|
575
|
+
const existingValue = existingPermission[permKey];
|
|
576
|
+
if (typeof existingValue === 'object' && existingValue !== null) {
|
|
577
|
+
const wildcard = existingValue['*'];
|
|
578
|
+
merged[permKey] = wildcard ? { '*': wildcard, ...patterns } : patterns;
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
return merged;
|
|
418
584
|
}
|
|
419
585
|
|
|
420
586
|
function getConfigPaths(workingDirectory) {
|
|
@@ -539,22 +705,23 @@ function getJsonWriteTarget(layers, preferredScope) {
|
|
|
539
705
|
}
|
|
540
706
|
|
|
541
707
|
function parseMdFile(filePath) {
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/);
|
|
545
|
-
|
|
546
|
-
if (!match) {
|
|
547
|
-
return { frontmatter: {}, body: content.trim() };
|
|
548
|
-
}
|
|
708
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
709
|
+
const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/);
|
|
549
710
|
|
|
550
|
-
|
|
551
|
-
|
|
711
|
+
if (!match) {
|
|
712
|
+
return { frontmatter: {}, body: content.trim() };
|
|
713
|
+
}
|
|
552
714
|
|
|
553
|
-
|
|
715
|
+
let frontmatter = {};
|
|
716
|
+
try {
|
|
717
|
+
frontmatter = yaml.parse(match[1]) || {};
|
|
554
718
|
} catch (error) {
|
|
555
|
-
console.
|
|
556
|
-
|
|
719
|
+
console.warn(`Failed to parse markdown frontmatter ${filePath}, treating as empty:`, error);
|
|
720
|
+
frontmatter = {};
|
|
557
721
|
}
|
|
722
|
+
|
|
723
|
+
const body = match[2].trim();
|
|
724
|
+
return { frontmatter, body };
|
|
558
725
|
}
|
|
559
726
|
|
|
560
727
|
function writeMdFile(filePath, frontmatter, body) {
|
|
@@ -606,12 +773,6 @@ function getAgentSources(agentName, workingDirectory) {
|
|
|
606
773
|
scope: jsonSource.exists ? jsonScope : null,
|
|
607
774
|
fields: []
|
|
608
775
|
},
|
|
609
|
-
json: {
|
|
610
|
-
exists: jsonSource.exists,
|
|
611
|
-
path: jsonPath,
|
|
612
|
-
scope: jsonSource.exists ? jsonScope : null,
|
|
613
|
-
fields: []
|
|
614
|
-
},
|
|
615
776
|
// Additional info about both levels
|
|
616
777
|
projectMd: {
|
|
617
778
|
exists: projectExists,
|
|
@@ -638,6 +799,48 @@ function getAgentSources(agentName, workingDirectory) {
|
|
|
638
799
|
return sources;
|
|
639
800
|
}
|
|
640
801
|
|
|
802
|
+
function getAgentConfig(agentName, workingDirectory) {
|
|
803
|
+
// Prefer markdown agents (project > user)
|
|
804
|
+
const projectPath = workingDirectory ? getProjectAgentPath(workingDirectory, agentName) : null;
|
|
805
|
+
const projectExists = projectPath && fs.existsSync(projectPath);
|
|
806
|
+
|
|
807
|
+
const userPath = getUserAgentPath(agentName);
|
|
808
|
+
const userExists = fs.existsSync(userPath);
|
|
809
|
+
|
|
810
|
+
if (projectExists || userExists) {
|
|
811
|
+
const mdPath = projectExists ? projectPath : userPath;
|
|
812
|
+
const { frontmatter, body } = parseMdFile(mdPath);
|
|
813
|
+
|
|
814
|
+
return {
|
|
815
|
+
source: 'md',
|
|
816
|
+
scope: projectExists ? AGENT_SCOPE.PROJECT : AGENT_SCOPE.USER,
|
|
817
|
+
config: {
|
|
818
|
+
...frontmatter,
|
|
819
|
+
...(typeof body === 'string' && body.length > 0 ? { prompt: body } : {}),
|
|
820
|
+
},
|
|
821
|
+
};
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
// Then fall back to opencode.json (highest-precedence entry)
|
|
825
|
+
const layers = readConfigLayers(workingDirectory);
|
|
826
|
+
const jsonSource = getJsonEntrySource(layers, 'agent', agentName);
|
|
827
|
+
|
|
828
|
+
if (jsonSource.exists && jsonSource.section) {
|
|
829
|
+
const scope = jsonSource.path === layers.paths.projectPath ? AGENT_SCOPE.PROJECT : AGENT_SCOPE.USER;
|
|
830
|
+
return {
|
|
831
|
+
source: 'json',
|
|
832
|
+
scope,
|
|
833
|
+
config: { ...jsonSource.section },
|
|
834
|
+
};
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
return {
|
|
838
|
+
source: 'none',
|
|
839
|
+
scope: null,
|
|
840
|
+
config: {},
|
|
841
|
+
};
|
|
842
|
+
}
|
|
843
|
+
|
|
641
844
|
function createAgent(agentName, config, workingDirectory, scope) {
|
|
642
845
|
ensureDirs();
|
|
643
846
|
|
|
@@ -693,7 +896,7 @@ function updateAgent(agentName, updates, workingDirectory) {
|
|
|
693
896
|
const hasJsonFields = jsonSource.exists && jsonSection && Object.keys(jsonSection).length > 0;
|
|
694
897
|
const jsonTarget = jsonSource.exists
|
|
695
898
|
? { config: jsonSource.config, path: jsonSource.path }
|
|
696
|
-
: getJsonWriteTarget(layers,
|
|
899
|
+
: getJsonWriteTarget(layers, AGENT_SCOPE.USER);
|
|
697
900
|
let config = jsonTarget.config || {};
|
|
698
901
|
|
|
699
902
|
// Determine if we should create a new md file:
|
|
@@ -742,7 +945,7 @@ function updateAgent(agentName, updates, workingDirectory) {
|
|
|
742
945
|
jsonModified = true;
|
|
743
946
|
continue;
|
|
744
947
|
}
|
|
745
|
-
|
|
948
|
+
|
|
746
949
|
// For JSON-only agents, store prompt inline in JSON
|
|
747
950
|
if (!config.agent) config.agent = {};
|
|
748
951
|
if (!config.agent[agentName]) config.agent[agentName] = {};
|
|
@@ -751,9 +954,79 @@ function updateAgent(agentName, updates, workingDirectory) {
|
|
|
751
954
|
continue;
|
|
752
955
|
}
|
|
753
956
|
|
|
957
|
+
// Special handling for permission field - uses location detection and preserves non-wildcards
|
|
958
|
+
if (field === 'permission') {
|
|
959
|
+
const permissionSource = getAgentPermissionSource(agentName, workingDirectory);
|
|
960
|
+
const newPermission = mergePermissionWithNonWildcards(value, permissionSource, agentName, workingDirectory);
|
|
961
|
+
|
|
962
|
+
if (permissionSource.source === 'md') {
|
|
963
|
+
// Write to existing .md file
|
|
964
|
+
const existingMdData = parseMdFile(permissionSource.path);
|
|
965
|
+
existingMdData.frontmatter.permission = newPermission;
|
|
966
|
+
writeMdFile(permissionSource.path, existingMdData.frontmatter, existingMdData.body);
|
|
967
|
+
console.log(`Updated permission in .md file: ${permissionSource.path}`);
|
|
968
|
+
} else if (permissionSource.source === 'json') {
|
|
969
|
+
// Write to existing JSON location
|
|
970
|
+
const existingConfig = readConfigFile(permissionSource.path);
|
|
971
|
+
if (!existingConfig.agent) existingConfig.agent = {};
|
|
972
|
+
if (!existingConfig.agent[agentName]) existingConfig.agent[agentName] = {};
|
|
973
|
+
existingConfig.agent[agentName].permission = newPermission;
|
|
974
|
+
writeConfig(existingConfig, permissionSource.path);
|
|
975
|
+
console.log(`Updated permission in JSON: ${permissionSource.path}`);
|
|
976
|
+
} else {
|
|
977
|
+
// Permission not defined anywhere - use agent's source location
|
|
978
|
+
if ((mdExists || creatingNewMd) && mdData) {
|
|
979
|
+
mdData.frontmatter.permission = newPermission;
|
|
980
|
+
mdModified = true;
|
|
981
|
+
} else if (hasJsonFields) {
|
|
982
|
+
// Agent exists in JSON - add permission there
|
|
983
|
+
if (!config.agent) config.agent = {};
|
|
984
|
+
if (!config.agent[agentName]) config.agent[agentName] = {};
|
|
985
|
+
config.agent[agentName].permission = newPermission;
|
|
986
|
+
jsonModified = true;
|
|
987
|
+
} else {
|
|
988
|
+
// Built-in agent with no config - write to project JSON if available, else user JSON
|
|
989
|
+
const writeTarget = workingDirectory
|
|
990
|
+
? { config: layers.projectConfig || {}, path: layers.paths.projectPath || layers.paths.userPath }
|
|
991
|
+
: { config: layers.userConfig || {}, path: layers.paths.userPath };
|
|
992
|
+
if (!writeTarget.config.agent) writeTarget.config.agent = {};
|
|
993
|
+
if (!writeTarget.config.agent[agentName]) writeTarget.config.agent[agentName] = {};
|
|
994
|
+
writeTarget.config.agent[agentName].permission = newPermission;
|
|
995
|
+
writeConfig(writeTarget.config, writeTarget.path);
|
|
996
|
+
console.log(`Created permission in JSON: ${writeTarget.path}`);
|
|
997
|
+
}
|
|
998
|
+
}
|
|
999
|
+
continue;
|
|
1000
|
+
}
|
|
1001
|
+
|
|
754
1002
|
const inMd = mdData?.frontmatter?.[field] !== undefined;
|
|
755
1003
|
const inJson = jsonSection?.[field] !== undefined;
|
|
756
1004
|
|
|
1005
|
+
if (value === null) {
|
|
1006
|
+
// Treat null as a request to remove the field.
|
|
1007
|
+
if (mdData && inMd) {
|
|
1008
|
+
delete mdData.frontmatter[field];
|
|
1009
|
+
mdModified = true;
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
if (inJson) {
|
|
1013
|
+
if (config.agent?.[agentName]) {
|
|
1014
|
+
delete config.agent[agentName][field];
|
|
1015
|
+
|
|
1016
|
+
if (Object.keys(config.agent[agentName]).length === 0) {
|
|
1017
|
+
delete config.agent[agentName];
|
|
1018
|
+
}
|
|
1019
|
+
if (Object.keys(config.agent).length === 0) {
|
|
1020
|
+
delete config.agent;
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
jsonModified = true;
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
continue;
|
|
1028
|
+
}
|
|
1029
|
+
|
|
757
1030
|
// JSON takes precedence over md, so update JSON first if field exists there
|
|
758
1031
|
if (inJson) {
|
|
759
1032
|
if (!config.agent) config.agent = {};
|
|
@@ -852,6 +1125,7 @@ function getCommandSources(commandName, workingDirectory) {
|
|
|
852
1125
|
const jsonSource = getJsonEntrySource(layers, 'command', commandName);
|
|
853
1126
|
const jsonSection = jsonSource.section;
|
|
854
1127
|
const jsonPath = jsonSource.path || layers.paths.customPath || layers.paths.projectPath || layers.paths.userPath;
|
|
1128
|
+
const jsonScope = jsonSource.path === layers.paths.projectPath ? COMMAND_SCOPE.PROJECT : COMMAND_SCOPE.USER;
|
|
855
1129
|
|
|
856
1130
|
const sources = {
|
|
857
1131
|
md: {
|
|
@@ -863,6 +1137,7 @@ function getCommandSources(commandName, workingDirectory) {
|
|
|
863
1137
|
json: {
|
|
864
1138
|
exists: jsonSource.exists,
|
|
865
1139
|
path: jsonPath,
|
|
1140
|
+
scope: jsonSource.exists ? jsonScope : null,
|
|
866
1141
|
fields: []
|
|
867
1142
|
},
|
|
868
1143
|
// Additional info about both levels
|
|
@@ -1373,6 +1648,8 @@ function deleteSkill(skillName, workingDirectory) {
|
|
|
1373
1648
|
export {
|
|
1374
1649
|
getAgentSources,
|
|
1375
1650
|
getAgentScope,
|
|
1651
|
+
getAgentPermissionSource,
|
|
1652
|
+
getAgentConfig,
|
|
1376
1653
|
createAgent,
|
|
1377
1654
|
updateAgent,
|
|
1378
1655
|
deleteAgent,
|