@karmaniverous/jeeves 0.4.6 → 0.5.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/README.md +56 -3
- package/content/skill.md +99 -0
- package/dist/cli/jeeves/index.js +660 -158
- package/dist/cli/plugin/index.js +206 -17
- package/dist/cli/service/index.js +63 -7
- package/dist/index.d.ts +393 -14
- package/dist/index.js +1175 -122
- package/package.json +2 -2
package/dist/cli/plugin/index.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { writeFileSync, renameSync, unlinkSync, existsSync,
|
|
2
|
+
import { writeFileSync, renameSync, unlinkSync, existsSync, mkdirSync, readFileSync, readdirSync, copyFileSync, rmSync } from 'node:fs';
|
|
3
3
|
import { dirname, join, resolve } from 'node:path';
|
|
4
4
|
import * as commander from 'commander';
|
|
5
|
+
import { packageDirectorySync } from 'package-directory';
|
|
5
6
|
import { lock } from 'proper-lockfile';
|
|
6
7
|
import 'semver';
|
|
7
8
|
import { homedir } from 'node:os';
|
|
@@ -111,7 +112,13 @@ const WORKSPACE_FILES = {
|
|
|
111
112
|
agents: 'AGENTS.md',
|
|
112
113
|
/** HEARTBEAT.md — platform status and health alerts. */
|
|
113
114
|
heartbeat: 'HEARTBEAT.md',
|
|
115
|
+
/** MEMORY.md — curated long-term memory. */
|
|
116
|
+
memory: 'MEMORY.md',
|
|
114
117
|
};
|
|
118
|
+
/** Skill directory name within workspace. */
|
|
119
|
+
const SKILLS_DIR = 'skills';
|
|
120
|
+
/** Jeeves skill directory name. */
|
|
121
|
+
const JEEVES_SKILL_DIR = 'jeeves';
|
|
115
122
|
/** Component versions state file name. */
|
|
116
123
|
const COMPONENT_VERSIONS_FILE = 'component-versions.json';
|
|
117
124
|
|
|
@@ -119,14 +126,14 @@ const COMPONENT_VERSIONS_FILE = 'component-versions.json';
|
|
|
119
126
|
* Core library version, inlined at build time.
|
|
120
127
|
*
|
|
121
128
|
* @remarks
|
|
122
|
-
* The `0.4.
|
|
129
|
+
* The `0.4.7` placeholder is replaced by
|
|
123
130
|
* `@rollup/plugin-replace` during the build with the actual version
|
|
124
131
|
* from `package.json`. This ensures the correct version survives
|
|
125
132
|
* when consumers bundle core into their own dist (where runtime
|
|
126
133
|
* `import.meta.url`-based resolution would find the wrong package.json).
|
|
127
134
|
*/
|
|
128
135
|
/** The core library version from package.json (inlined at build time). */
|
|
129
|
-
const CORE_VERSION = '0.4.
|
|
136
|
+
const CORE_VERSION = '0.4.7';
|
|
130
137
|
|
|
131
138
|
/**
|
|
132
139
|
* Shared file I/O helpers for managed section operations.
|
|
@@ -224,6 +231,30 @@ function readComponentVersions(coreConfigDir) {
|
|
|
224
231
|
return {};
|
|
225
232
|
}
|
|
226
233
|
}
|
|
234
|
+
/**
|
|
235
|
+
* Write a component's version entry to the shared state file.
|
|
236
|
+
*
|
|
237
|
+
* @remarks
|
|
238
|
+
* Reads the existing file, merges the new entry, and writes atomically.
|
|
239
|
+
*
|
|
240
|
+
* @param coreConfigDir - Path to the core config directory.
|
|
241
|
+
* @param options - Component version data to write.
|
|
242
|
+
*/
|
|
243
|
+
function writeComponentVersion(coreConfigDir, options) {
|
|
244
|
+
const existing = readComponentVersions(coreConfigDir);
|
|
245
|
+
existing[options.componentName] = {
|
|
246
|
+
pluginVersion: options.pluginVersion,
|
|
247
|
+
servicePackage: options.servicePackage,
|
|
248
|
+
pluginPackage: options.pluginPackage,
|
|
249
|
+
updatedAt: new Date().toISOString(),
|
|
250
|
+
};
|
|
251
|
+
const filePath = join(coreConfigDir, COMPONENT_VERSIONS_FILE);
|
|
252
|
+
const dir = dirname(filePath);
|
|
253
|
+
if (!existsSync(dir)) {
|
|
254
|
+
mkdirSync(dir, { recursive: true });
|
|
255
|
+
}
|
|
256
|
+
atomicWrite(filePath, JSON.stringify(existing, null, 2) + '\n');
|
|
257
|
+
}
|
|
227
258
|
/**
|
|
228
259
|
* Remove a component's version entry from the shared state file.
|
|
229
260
|
*
|
|
@@ -683,6 +714,129 @@ function buildWithSections(beforeContent, userContent, sections, markers, coreVe
|
|
|
683
714
|
return parts.join('\n');
|
|
684
715
|
}
|
|
685
716
|
|
|
717
|
+
var skillContent = `---
|
|
718
|
+
name: jeeves
|
|
719
|
+
description: Jeeves platform architecture, data flow, component interaction, scripts repo, and coordination knowledge. Use when making architectural decisions, coordinating across components, checking platform health, managing service lifecycle, or working with the scripts repo.
|
|
720
|
+
---
|
|
721
|
+
|
|
722
|
+
# Jeeves Platform Skill
|
|
723
|
+
|
|
724
|
+
## Platform Architecture
|
|
725
|
+
|
|
726
|
+
Jeeves is a four-component platform coordinated by a shared library (\`@karmaniverous/jeeves\`):
|
|
727
|
+
|
|
728
|
+
| Component | Role | Port |
|
|
729
|
+
|-----------|------|------|
|
|
730
|
+
| **jeeves-runner** | Execute: scheduled jobs, SQLite state, HTTP API | 1937 |
|
|
731
|
+
| **jeeves-watcher** | Index: file→Qdrant semantic indexing, inference rules | 1936 |
|
|
732
|
+
| **jeeves-server** | Present: web UI, file browser, doc render, export | 1934 |
|
|
733
|
+
| **jeeves-meta** | Distill: LLM synthesis, .meta/ directories, scheduling | 1938 |
|
|
734
|
+
|
|
735
|
+
Core (\`@karmaniverous/jeeves\`) is a **library + CLI**, not a service. No port.
|
|
736
|
+
|
|
737
|
+
## Data Flow
|
|
738
|
+
|
|
739
|
+
\`\`\`
|
|
740
|
+
Files → Watcher (index) → Qdrant → Meta (synthesize) → .meta/ → Watcher (re-index)
|
|
741
|
+
↓
|
|
742
|
+
Runner (schedule) → Scripts → Services ← Server (present) ← Browser
|
|
743
|
+
\`\`\`
|
|
744
|
+
|
|
745
|
+
## Component Interaction
|
|
746
|
+
|
|
747
|
+
- **Watcher** indexes files into Qdrant with inference rules and enrichments.
|
|
748
|
+
- **Meta** reads from Qdrant, synthesizes \`.meta/\` directories, which watcher re-indexes.
|
|
749
|
+
- **Runner** executes scheduled scripts that may call any service's HTTP API.
|
|
750
|
+
- **Server** presents files, renders documents, and provides the event gateway.
|
|
751
|
+
- **Core** provides shared content management (TOOLS.md, SOUL.md, AGENTS.md), service discovery, config resolution, and the component SDK.
|
|
752
|
+
|
|
753
|
+
## Service Discovery
|
|
754
|
+
|
|
755
|
+
Services find each other via config resolution:
|
|
756
|
+
1. Component's own config file (\`{configRoot}/jeeves-{name}/config.json\`)
|
|
757
|
+
2. Core config file (\`{configRoot}/jeeves-core/config.json\`)
|
|
758
|
+
3. Default port constants
|
|
759
|
+
|
|
760
|
+
## Scripts Repo
|
|
761
|
+
|
|
762
|
+
Location: \`{configRoot}/jeeves-core/scripts/\`
|
|
763
|
+
Template: \`@karmaniverous/jeeves-scripts-template\`
|
|
764
|
+
|
|
765
|
+
Scripts use utilities from \`@karmaniverous/jeeves\` (general) and \`@karmaniverous/jeeves-runner\` (runner-specific). Any script that could be useful outside runner scheduling belongs in core.
|
|
766
|
+
|
|
767
|
+
## Managed Content System
|
|
768
|
+
|
|
769
|
+
Core maintains managed sections in workspace files using comment markers:
|
|
770
|
+
- **TOOLS.md** — Component sections (section mode) + Platform section
|
|
771
|
+
- **SOUL.md** — Professional discipline and behavioral foundations (block mode)
|
|
772
|
+
- **AGENTS.md** — Operational protocols and memory architecture (block mode)
|
|
773
|
+
- **HEARTBEAT.md** — Platform health status (heading-based)
|
|
774
|
+
|
|
775
|
+
Managed blocks are stationary after initial insertion. Cleanup detection uses Jaccard similarity on 3-word shingles. Cleanup escalation spawns a gateway session when orphaned content is detected.
|
|
776
|
+
|
|
777
|
+
## Workspace Configuration
|
|
778
|
+
|
|
779
|
+
\`jeeves.config.json\` at workspace root provides shared defaults:
|
|
780
|
+
- Precedence: CLI flags → env vars → file → defaults
|
|
781
|
+
- Namespaced: \`core.*\` (workspace, configRoot, gatewayUrl) and \`memory.*\` (budget, warningThreshold, staleDays)
|
|
782
|
+
- Inspect with \`jeeves config [jsonpath]\`
|
|
783
|
+
|
|
784
|
+
## HEARTBEAT Protocol
|
|
785
|
+
|
|
786
|
+
The HEARTBEAT system uses a state machine per component:
|
|
787
|
+
\`not_installed → deps_missing → config_missing → service_not_installed → service_stopped → healthy\`
|
|
788
|
+
|
|
789
|
+
Dependency-aware: hard deps block alerts, soft deps add informational notes. Declined components are tracked via heading suffix.
|
|
790
|
+
|
|
791
|
+
## Plugin Lifecycle
|
|
792
|
+
|
|
793
|
+
\`\`\`bash
|
|
794
|
+
# Core install (seed workspace content)
|
|
795
|
+
npx @karmaniverous/jeeves install
|
|
796
|
+
|
|
797
|
+
# Component plugin install
|
|
798
|
+
npx @karmaniverous/jeeves-{component}-openclaw install
|
|
799
|
+
|
|
800
|
+
# Component plugin uninstall
|
|
801
|
+
npx @karmaniverous/jeeves-{component}-openclaw uninstall
|
|
802
|
+
|
|
803
|
+
# Core uninstall (remove managed sections)
|
|
804
|
+
npx @karmaniverous/jeeves uninstall
|
|
805
|
+
\`\`\`
|
|
806
|
+
|
|
807
|
+
## Memory Hygiene
|
|
808
|
+
|
|
809
|
+
MEMORY.md has a character budget (default 20,000). Core tracks:
|
|
810
|
+
- Character count and usage percentage
|
|
811
|
+
- Warning at 80% of budget
|
|
812
|
+
- Stale section candidates (H2 sections whose most recent ISO date exceeds the staleness threshold)
|
|
813
|
+
- Evergreen sections (no dates) are never flagged
|
|
814
|
+
|
|
815
|
+
Review is human/agent-mediated — core does not auto-delete.
|
|
816
|
+
`;
|
|
817
|
+
|
|
818
|
+
/**
|
|
819
|
+
* Skill seeding: write the `jeeves` workspace skill unconditionally.
|
|
820
|
+
*
|
|
821
|
+
* @remarks
|
|
822
|
+
* The skill file is entirely generated — no user-authored content (Decision 48).
|
|
823
|
+
* Every installer (core CLI and component plugins) writes it unconditionally.
|
|
824
|
+
* Content is inlined at build time via `rollup-plugin-md.ts`.
|
|
825
|
+
*/
|
|
826
|
+
/**
|
|
827
|
+
* Seed the jeeves workspace skill file.
|
|
828
|
+
*
|
|
829
|
+
* @param workspacePath - Workspace root directory.
|
|
830
|
+
*/
|
|
831
|
+
function seedSkill(workspacePath) {
|
|
832
|
+
const skillDir = join(workspacePath, SKILLS_DIR, JEEVES_SKILL_DIR);
|
|
833
|
+
if (!existsSync(skillDir)) {
|
|
834
|
+
mkdirSync(skillDir, { recursive: true });
|
|
835
|
+
}
|
|
836
|
+
const skillPath = join(skillDir, 'SKILL.md');
|
|
837
|
+
writeFileSync(skillPath, skillContent, 'utf-8');
|
|
838
|
+
}
|
|
839
|
+
|
|
686
840
|
/**
|
|
687
841
|
* OpenClaw configuration helpers for plugin CLI installers.
|
|
688
842
|
*
|
|
@@ -802,13 +956,9 @@ function patchConfig(config, pluginId, mode) {
|
|
|
802
956
|
}
|
|
803
957
|
|
|
804
958
|
/**
|
|
805
|
-
*
|
|
959
|
+
* Internal helpers for the plugin installer CLI.
|
|
806
960
|
*
|
|
807
|
-
* @
|
|
808
|
-
* Produces a Commander program with `install` and `uninstall` commands
|
|
809
|
-
* that handle the full plugin lifecycle: copy dist to extensions,
|
|
810
|
-
* patch OpenClaw config, manage HEARTBEAT entries, and clean up
|
|
811
|
-
* managed sections on uninstall.
|
|
961
|
+
* @module
|
|
812
962
|
*/
|
|
813
963
|
/**
|
|
814
964
|
* Derive a component name from a plugin ID.
|
|
@@ -823,7 +973,7 @@ function deriveComponentName(pluginId) {
|
|
|
823
973
|
return pluginId.replace(/^jeeves-/, '').replace(/-openclaw$/, '');
|
|
824
974
|
}
|
|
825
975
|
/**
|
|
826
|
-
* Copy all files from source directory to destination.
|
|
976
|
+
* Copy all files from source directory to destination, recursively.
|
|
827
977
|
*
|
|
828
978
|
* @param srcDir - Source directory.
|
|
829
979
|
* @param destDir - Destination directory.
|
|
@@ -857,6 +1007,12 @@ function readJsonFile(filePath) {
|
|
|
857
1007
|
return {};
|
|
858
1008
|
}
|
|
859
1009
|
}
|
|
1010
|
+
|
|
1011
|
+
/**
|
|
1012
|
+
* Factory for the standard `-openclaw` plugin installer CLI.
|
|
1013
|
+
*
|
|
1014
|
+
* @module
|
|
1015
|
+
*/
|
|
860
1016
|
/**
|
|
861
1017
|
* Create a standard plugin installer CLI program.
|
|
862
1018
|
*
|
|
@@ -882,6 +1038,16 @@ function createPluginCli(options) {
|
|
|
882
1038
|
const extensionsDir = join(openClawHome, 'extensions', pluginId);
|
|
883
1039
|
console.log(`Copying dist to ${extensionsDir}...`);
|
|
884
1040
|
copyDistFiles(distDir, extensionsDir);
|
|
1041
|
+
// Copy package.json and openclaw.plugin.json from package root
|
|
1042
|
+
const pkgRoot = packageDirectorySync({ cwd: distDir });
|
|
1043
|
+
if (pkgRoot) {
|
|
1044
|
+
for (const file of ['package.json', 'openclaw.plugin.json']) {
|
|
1045
|
+
const src = join(pkgRoot, file);
|
|
1046
|
+
if (existsSync(src)) {
|
|
1047
|
+
copyFileSync(src, join(extensionsDir, file));
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
885
1051
|
console.log(' ✓ Dist files copied');
|
|
886
1052
|
// 2. Patch openclaw.json
|
|
887
1053
|
console.log('Patching OpenClaw config...');
|
|
@@ -910,7 +1076,7 @@ function createPluginCli(options) {
|
|
|
910
1076
|
for (const msg of messages) {
|
|
911
1077
|
console.log(` ✓ ${msg}`);
|
|
912
1078
|
}
|
|
913
|
-
// 4. Write initial HEARTBEAT entry
|
|
1079
|
+
// 4. Write initial HEARTBEAT entry and seed jeeves skill
|
|
914
1080
|
try {
|
|
915
1081
|
const cfgRoot = opts.configRoot;
|
|
916
1082
|
const agents = config.agents;
|
|
@@ -925,7 +1091,6 @@ function createPluginCli(options) {
|
|
|
925
1091
|
: '';
|
|
926
1092
|
const parsed = parseHeartbeat(existing);
|
|
927
1093
|
const fullName = `jeeves-${componentName}`;
|
|
928
|
-
// Only add if not already present
|
|
929
1094
|
const hasEntry = parsed.entries.some((e) => e.name === fullName);
|
|
930
1095
|
if (!hasEntry) {
|
|
931
1096
|
parsed.entries.push({
|
|
@@ -941,10 +1106,36 @@ function createPluginCli(options) {
|
|
|
941
1106
|
catch {
|
|
942
1107
|
console.log(' ⚠ Could not write HEARTBEAT entry');
|
|
943
1108
|
}
|
|
1109
|
+
try {
|
|
1110
|
+
seedSkill(ws);
|
|
1111
|
+
console.log(' ✓ Jeeves skill seeded');
|
|
1112
|
+
}
|
|
1113
|
+
catch {
|
|
1114
|
+
console.log(' ⚠ Could not seed Jeeves skill');
|
|
1115
|
+
}
|
|
944
1116
|
}
|
|
945
1117
|
}
|
|
946
1118
|
catch {
|
|
947
|
-
// HEARTBEAT
|
|
1119
|
+
// HEARTBEAT + skill seeding are best-effort during install
|
|
1120
|
+
}
|
|
1121
|
+
// 5. Write component version
|
|
1122
|
+
try {
|
|
1123
|
+
init({
|
|
1124
|
+
workspacePath: opts.workspace ?? '.',
|
|
1125
|
+
configRoot: opts.configRoot,
|
|
1126
|
+
});
|
|
1127
|
+
const pkgJsonPath = join(extensionsDir, 'package.json');
|
|
1128
|
+
const pkgJson = readJsonFile(pkgJsonPath);
|
|
1129
|
+
const pluginVersion = typeof pkgJson.version === 'string' ? pkgJson.version : undefined;
|
|
1130
|
+
writeComponentVersion(getCoreConfigDir(), {
|
|
1131
|
+
componentName,
|
|
1132
|
+
pluginPackage,
|
|
1133
|
+
pluginVersion,
|
|
1134
|
+
});
|
|
1135
|
+
console.log(' ✓ Component version written');
|
|
1136
|
+
}
|
|
1137
|
+
catch {
|
|
1138
|
+
console.log(' ⚠ Could not write component version');
|
|
948
1139
|
}
|
|
949
1140
|
console.log();
|
|
950
1141
|
console.log(`✅ ${pluginPackage} installed.`);
|
|
@@ -974,10 +1165,9 @@ function createPluginCli(options) {
|
|
|
974
1165
|
}
|
|
975
1166
|
// 3. Remove TOOLS.md section
|
|
976
1167
|
try {
|
|
977
|
-
const cfgRoot = opts.configRoot;
|
|
978
1168
|
const ws = opts.workspace;
|
|
979
1169
|
if (ws) {
|
|
980
|
-
init({ workspacePath: ws, configRoot:
|
|
1170
|
+
init({ workspacePath: ws, configRoot: opts.configRoot });
|
|
981
1171
|
const sectionId = componentName.charAt(0).toUpperCase() + componentName.slice(1);
|
|
982
1172
|
const toolsPath = join(ws, WORKSPACE_FILES.tools);
|
|
983
1173
|
if (existsSync(toolsPath)) {
|
|
@@ -994,10 +1184,9 @@ function createPluginCli(options) {
|
|
|
994
1184
|
}
|
|
995
1185
|
// 4. Remove component-versions.json entry
|
|
996
1186
|
try {
|
|
997
|
-
const cfgRoot = opts.configRoot;
|
|
998
1187
|
init({
|
|
999
1188
|
workspacePath: opts.workspace ?? '.',
|
|
1000
|
-
configRoot:
|
|
1189
|
+
configRoot: opts.configRoot,
|
|
1001
1190
|
});
|
|
1002
1191
|
removeComponentVersion(getCoreConfigDir(), componentName);
|
|
1003
1192
|
console.log(' ✓ Component version entry removed');
|
|
@@ -697,17 +697,73 @@ function createServiceManager(descriptor) {
|
|
|
697
697
|
}
|
|
698
698
|
|
|
699
699
|
/**
|
|
700
|
-
*
|
|
700
|
+
* Workspace-level shared configuration: `jeeves.config.json`.
|
|
701
701
|
*
|
|
702
702
|
* @remarks
|
|
703
|
-
*
|
|
704
|
-
*
|
|
705
|
-
*
|
|
703
|
+
* Lives at the OpenClaw workspace root alongside TOOLS.md and SOUL.md.
|
|
704
|
+
* Provides namespaced shared defaults consumed by the root Jeeves CLI.
|
|
705
|
+
* Resolution precedence: CLI flags → env vars → jeeves.config.json → defaults.
|
|
706
|
+
*
|
|
707
|
+
* This does not replace component-owned config schemas (Decision 41).
|
|
708
|
+
*/
|
|
709
|
+
/** Core shared config section. */
|
|
710
|
+
const workspaceCoreConfigSchema = z
|
|
711
|
+
.object({
|
|
712
|
+
/** Workspace root path. */
|
|
713
|
+
workspace: z.string().optional().describe('Workspace root path'),
|
|
714
|
+
/** Platform config root path. */
|
|
715
|
+
configRoot: z.string().optional().describe('Platform config root path'),
|
|
716
|
+
/** OpenClaw gateway URL. */
|
|
717
|
+
gatewayUrl: z.string().optional().describe('OpenClaw gateway URL'),
|
|
718
|
+
})
|
|
719
|
+
.partial();
|
|
720
|
+
/** Memory shared config section. */
|
|
721
|
+
const workspaceMemoryConfigSchema = z
|
|
722
|
+
.object({
|
|
723
|
+
/** MEMORY.md character budget. */
|
|
724
|
+
budget: z.number().int().positive().optional().describe('Memory budget'),
|
|
725
|
+
/** Warning threshold as a fraction of budget. */
|
|
726
|
+
warningThreshold: z
|
|
727
|
+
.number()
|
|
728
|
+
.min(0)
|
|
729
|
+
.max(1)
|
|
730
|
+
.optional()
|
|
731
|
+
.describe('Memory warning threshold'),
|
|
732
|
+
/** Staleness threshold in days. */
|
|
733
|
+
staleDays: z
|
|
734
|
+
.number()
|
|
735
|
+
.int()
|
|
736
|
+
.positive()
|
|
737
|
+
.optional()
|
|
738
|
+
.describe('Memory staleness threshold in days'),
|
|
739
|
+
})
|
|
740
|
+
.partial();
|
|
741
|
+
/** Workspace config Zod schema. */
|
|
742
|
+
z.object({
|
|
743
|
+
/** JSON Schema pointer for IDE autocomplete. */
|
|
744
|
+
$schema: z.string().optional().describe('JSON Schema pointer'),
|
|
745
|
+
/** Core shared defaults. */
|
|
746
|
+
core: workspaceCoreConfigSchema.optional(),
|
|
747
|
+
/** Memory hygiene shared defaults. */
|
|
748
|
+
memory: workspaceMemoryConfigSchema.optional(),
|
|
749
|
+
});
|
|
750
|
+
/** Built-in workspace config defaults. */
|
|
751
|
+
const WORKSPACE_CONFIG_DEFAULTS = {
|
|
752
|
+
core: {
|
|
753
|
+
workspace: '.',
|
|
754
|
+
configRoot: './config'}};
|
|
755
|
+
|
|
756
|
+
/**
|
|
757
|
+
* Shared CLI defaults and resolution for Jeeves CLI commands.
|
|
758
|
+
*
|
|
759
|
+
* @remarks
|
|
760
|
+
* All root CLI commands share workspace/config-root resolution. Values follow
|
|
761
|
+
* the shared precedence model: flags → env → jeeves.config.json → defaults.
|
|
706
762
|
*/
|
|
707
|
-
/** Default workspace path
|
|
708
|
-
const DEFAULT_WORKSPACE =
|
|
763
|
+
/** Default workspace path. */
|
|
764
|
+
const DEFAULT_WORKSPACE = WORKSPACE_CONFIG_DEFAULTS.core.workspace;
|
|
709
765
|
/** Default config root path. */
|
|
710
|
-
const DEFAULT_CONFIG_ROOT =
|
|
766
|
+
const DEFAULT_CONFIG_ROOT = WORKSPACE_CONFIG_DEFAULTS.core.configRoot;
|
|
711
767
|
|
|
712
768
|
/**
|
|
713
769
|
* Factory for the standard Jeeves service CLI.
|