- Add full Telegram bot functionality with Z.AI API integration
- Implement 4 tools: Bash, FileEdit, WebSearch, Git
- Add 3 agents: Code Reviewer, Architect, DevOps Engineer
- Add 6 skills for common coding tasks
- Add systemd service file for 24/7 operation
- Add nginx configuration for HTTPS webhook
- Add comprehensive documentation
- Implement WebSocket server for real-time updates
- Add logging system with Winston
- Add environment validation
🤖 zCode CLI X - Agentic coder with Z.AI + Telegram integration
149 lines
5.4 KiB
JavaScript
149 lines
5.4 KiB
JavaScript
/*
|
|
* Copyright The OpenTelemetry Authors
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
import { diag } from '@opentelemetry/api';
|
|
import { SDK_INFO } from '@opentelemetry/core';
|
|
import { ATTR_SERVICE_NAME, ATTR_TELEMETRY_SDK_LANGUAGE, ATTR_TELEMETRY_SDK_NAME, ATTR_TELEMETRY_SDK_VERSION, } from '@opentelemetry/semantic-conventions';
|
|
import { defaultServiceName } from './default-service-name';
|
|
import { isPromiseLike } from './utils';
|
|
class ResourceImpl {
|
|
_rawAttributes;
|
|
_asyncAttributesPending = false;
|
|
_schemaUrl;
|
|
_memoizedAttributes;
|
|
static FromAttributeList(attributes, options) {
|
|
const res = new ResourceImpl({}, options);
|
|
res._rawAttributes = guardedRawAttributes(attributes);
|
|
res._asyncAttributesPending =
|
|
attributes.filter(([_, val]) => isPromiseLike(val)).length > 0;
|
|
return res;
|
|
}
|
|
constructor(
|
|
/**
|
|
* A dictionary of attributes with string keys and values that provide
|
|
* information about the entity as numbers, strings or booleans
|
|
* TODO: Consider to add check/validation on attributes.
|
|
*/
|
|
resource, options) {
|
|
const attributes = resource.attributes ?? {};
|
|
this._rawAttributes = Object.entries(attributes).map(([k, v]) => {
|
|
if (isPromiseLike(v)) {
|
|
// side-effect
|
|
this._asyncAttributesPending = true;
|
|
}
|
|
return [k, v];
|
|
});
|
|
this._rawAttributes = guardedRawAttributes(this._rawAttributes);
|
|
this._schemaUrl = validateSchemaUrl(options?.schemaUrl);
|
|
}
|
|
get asyncAttributesPending() {
|
|
return this._asyncAttributesPending;
|
|
}
|
|
async waitForAsyncAttributes() {
|
|
if (!this.asyncAttributesPending) {
|
|
return;
|
|
}
|
|
for (let i = 0; i < this._rawAttributes.length; i++) {
|
|
const [k, v] = this._rawAttributes[i];
|
|
this._rawAttributes[i] = [k, isPromiseLike(v) ? await v : v];
|
|
}
|
|
this._asyncAttributesPending = false;
|
|
}
|
|
get attributes() {
|
|
if (this.asyncAttributesPending) {
|
|
diag.error('Accessing resource attributes before async attributes settled');
|
|
}
|
|
if (this._memoizedAttributes) {
|
|
return this._memoizedAttributes;
|
|
}
|
|
const attrs = {};
|
|
for (const [k, v] of this._rawAttributes) {
|
|
if (isPromiseLike(v)) {
|
|
diag.debug(`Unsettled resource attribute ${k} skipped`);
|
|
continue;
|
|
}
|
|
if (v != null) {
|
|
attrs[k] ??= v;
|
|
}
|
|
}
|
|
// only memoize output if all attributes are settled
|
|
if (!this._asyncAttributesPending) {
|
|
this._memoizedAttributes = attrs;
|
|
}
|
|
return attrs;
|
|
}
|
|
getRawAttributes() {
|
|
return this._rawAttributes;
|
|
}
|
|
get schemaUrl() {
|
|
return this._schemaUrl;
|
|
}
|
|
merge(resource) {
|
|
if (resource == null)
|
|
return this;
|
|
// Order is important
|
|
// Spec states incoming attributes override existing attributes
|
|
const mergedSchemaUrl = mergeSchemaUrl(this, resource);
|
|
const mergedOptions = mergedSchemaUrl
|
|
? { schemaUrl: mergedSchemaUrl }
|
|
: undefined;
|
|
return ResourceImpl.FromAttributeList([...resource.getRawAttributes(), ...this.getRawAttributes()], mergedOptions);
|
|
}
|
|
}
|
|
export function resourceFromAttributes(attributes, options) {
|
|
return ResourceImpl.FromAttributeList(Object.entries(attributes), options);
|
|
}
|
|
export function resourceFromDetectedResource(detectedResource, options) {
|
|
return new ResourceImpl(detectedResource, options);
|
|
}
|
|
export function emptyResource() {
|
|
return resourceFromAttributes({});
|
|
}
|
|
export function defaultResource() {
|
|
return resourceFromAttributes({
|
|
[ATTR_SERVICE_NAME]: defaultServiceName(),
|
|
[ATTR_TELEMETRY_SDK_LANGUAGE]: SDK_INFO[ATTR_TELEMETRY_SDK_LANGUAGE],
|
|
[ATTR_TELEMETRY_SDK_NAME]: SDK_INFO[ATTR_TELEMETRY_SDK_NAME],
|
|
[ATTR_TELEMETRY_SDK_VERSION]: SDK_INFO[ATTR_TELEMETRY_SDK_VERSION],
|
|
});
|
|
}
|
|
function guardedRawAttributes(attributes) {
|
|
return attributes.map(([k, v]) => {
|
|
if (isPromiseLike(v)) {
|
|
return [
|
|
k,
|
|
v.catch(err => {
|
|
diag.debug('promise rejection for resource attribute: %s - %s', k, err);
|
|
return undefined;
|
|
}),
|
|
];
|
|
}
|
|
return [k, v];
|
|
});
|
|
}
|
|
function validateSchemaUrl(schemaUrl) {
|
|
if (typeof schemaUrl === 'string' || schemaUrl === undefined) {
|
|
return schemaUrl;
|
|
}
|
|
diag.warn('Schema URL must be string or undefined, got %s. Schema URL will be ignored.', schemaUrl);
|
|
return undefined;
|
|
}
|
|
function mergeSchemaUrl(old, updating) {
|
|
const oldSchemaUrl = old?.schemaUrl;
|
|
const updatingSchemaUrl = updating?.schemaUrl;
|
|
const isOldEmpty = oldSchemaUrl === undefined || oldSchemaUrl === '';
|
|
const isUpdatingEmpty = updatingSchemaUrl === undefined || updatingSchemaUrl === '';
|
|
if (isOldEmpty) {
|
|
return updatingSchemaUrl;
|
|
}
|
|
if (isUpdatingEmpty) {
|
|
return oldSchemaUrl;
|
|
}
|
|
if (oldSchemaUrl === updatingSchemaUrl) {
|
|
return oldSchemaUrl;
|
|
}
|
|
diag.warn('Schema URL merge conflict: old resource has "%s", updating resource has "%s". Resulting resource will have undefined Schema URL.', oldSchemaUrl, updatingSchemaUrl);
|
|
return undefined;
|
|
}
|
|
//# sourceMappingURL=ResourceImpl.js.map
|